aboutsummaryrefslogtreecommitdiffstats
path: root/branches/gpgme-1-0-branch/gpgme
diff options
context:
space:
mode:
Diffstat (limited to 'branches/gpgme-1-0-branch/gpgme')
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ChangeLog4546
-rw-r--r--branches/gpgme-1-0-branch/gpgme/Makefile.am126
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath-compat.c185
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath-pth-compat.c123
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath-pth.c177
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath-pthread-compat.c104
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath-pthread.c175
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath.c142
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ath.h106
-rw-r--r--branches/gpgme-1-0-branch/gpgme/context.h111
-rw-r--r--branches/gpgme-1-0-branch/gpgme/conversion.c411
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data-compat.c208
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data-fd.c69
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data-mem.c223
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data-stream.c87
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data-user.c76
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data.c242
-rw-r--r--branches/gpgme-1-0-branch/gpgme/data.h120
-rw-r--r--branches/gpgme-1-0-branch/gpgme/debug.c220
-rw-r--r--branches/gpgme-1-0-branch/gpgme/debug.h110
-rw-r--r--branches/gpgme-1-0-branch/gpgme/decrypt-verify.c102
-rw-r--r--branches/gpgme-1-0-branch/gpgme/decrypt.c238
-rw-r--r--branches/gpgme-1-0-branch/gpgme/delete.c108
-rw-r--r--branches/gpgme-1-0-branch/gpgme/edit.c169
-rw-r--r--branches/gpgme-1-0-branch/gpgme/encrypt-sign.c109
-rw-r--r--branches/gpgme-1-0-branch/gpgme/encrypt.c221
-rw-r--r--branches/gpgme-1-0-branch/gpgme/engine-backend.h97
-rw-r--r--branches/gpgme-1-0-branch/gpgme/engine-gpgsm.c1595
-rw-r--r--branches/gpgme-1-0-branch/gpgme/engine.c499
-rw-r--r--branches/gpgme-1-0-branch/gpgme/engine.h115
-rw-r--r--branches/gpgme-1-0-branch/gpgme/error.c91
-rw-r--r--branches/gpgme-1-0-branch/gpgme/export.c116
-rw-r--r--branches/gpgme-1-0-branch/gpgme/funopen.c44
-rw-r--r--branches/gpgme-1-0-branch/gpgme/genkey.c204
-rw-r--r--branches/gpgme-1-0-branch/gpgme/get-env.c58
-rw-r--r--branches/gpgme-1-0-branch/gpgme/gpgme-config.in132
-rw-r--r--branches/gpgme-1-0-branch/gpgme/gpgme.c469
-rw-r--r--branches/gpgme-1-0-branch/gpgme/gpgme.h1558
-rw-r--r--branches/gpgme-1-0-branch/gpgme/gpgme.m4236
-rw-r--r--branches/gpgme-1-0-branch/gpgme/import.c272
-rw-r--r--branches/gpgme-1-0-branch/gpgme/io.h65
-rw-r--r--branches/gpgme-1-0-branch/gpgme/isascii.c29
-rw-r--r--branches/gpgme-1-0-branch/gpgme/key.c711
-rw-r--r--branches/gpgme-1-0-branch/gpgme/keylist.c874
-rw-r--r--branches/gpgme-1-0-branch/gpgme/libgpgme.vers146
-rw-r--r--branches/gpgme-1-0-branch/gpgme/memrchr.c39
-rwxr-xr-xbranches/gpgme-1-0-branch/gpgme/mkstatus52
-rw-r--r--branches/gpgme-1-0-branch/gpgme/op-support.c201
-rw-r--r--branches/gpgme-1-0-branch/gpgme/ops.h143
-rw-r--r--branches/gpgme-1-0-branch/gpgme/passphrase.c160
-rw-r--r--branches/gpgme-1-0-branch/gpgme/posix-io.c410
-rw-r--r--branches/gpgme-1-0-branch/gpgme/posix-sema.c63
-rw-r--r--branches/gpgme-1-0-branch/gpgme/posix-util.c49
-rw-r--r--branches/gpgme-1-0-branch/gpgme/progress.c80
-rw-r--r--branches/gpgme-1-0-branch/gpgme/putc_unlocked.c31
-rw-r--r--branches/gpgme-1-0-branch/gpgme/rungpg.c1688
-rw-r--r--branches/gpgme-1-0-branch/gpgme/sema.h66
-rw-r--r--branches/gpgme-1-0-branch/gpgme/sign.c327
-rw-r--r--branches/gpgme-1-0-branch/gpgme/signers.c94
-rw-r--r--branches/gpgme-1-0-branch/gpgme/stpcpy.c50
-rw-r--r--branches/gpgme-1-0-branch/gpgme/trust-item.c170
-rw-r--r--branches/gpgme-1-0-branch/gpgme/trustlist.c245
-rw-r--r--branches/gpgme-1-0-branch/gpgme/util.h90
-rw-r--r--branches/gpgme-1-0-branch/gpgme/vasprintf.c192
-rw-r--r--branches/gpgme-1-0-branch/gpgme/verify.c879
-rw-r--r--branches/gpgme-1-0-branch/gpgme/version.c219
-rw-r--r--branches/gpgme-1-0-branch/gpgme/w32-io.c1117
-rw-r--r--branches/gpgme-1-0-branch/gpgme/w32-sema.c113
-rw-r--r--branches/gpgme-1-0-branch/gpgme/w32-util.c144
-rw-r--r--branches/gpgme-1-0-branch/gpgme/wait-global.c357
-rw-r--r--branches/gpgme-1-0-branch/gpgme/wait-private.c150
-rw-r--r--branches/gpgme-1-0-branch/gpgme/wait-user.c124
-rw-r--r--branches/gpgme-1-0-branch/gpgme/wait.c168
-rw-r--r--branches/gpgme-1-0-branch/gpgme/wait.h79
74 files changed, 23319 insertions, 0 deletions
diff --git a/branches/gpgme-1-0-branch/gpgme/ChangeLog b/branches/gpgme-1-0-branch/gpgme/ChangeLog
new file mode 100644
index 00000000..6b2539d6
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ChangeLog
@@ -0,0 +1,4546 @@
+2004-10-03 Marcus Brinkmann <[email protected]>
+
+ * verify.c (parse_trust): If no reason is provided, set
+ SIG->validity_reason to 0.
+ (calc_sig_summary): Set GPGME_SIGSUM_CRL_TOO_OLD if appropriate.
+
+2004-10-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (map_assuan_error): Return 0 if ERR is 0.
+ (start): Call map_assuan_error on return value of
+ assuan_write_line.
+
+2004-10-05 Marcus Brinkmann <[email protected]>
+
+ * op-support.c (_gpgme_op_data_lookup): Use char pointer for
+ pointer arithmetic.
+
+2004-09-30 Marcus Brinkmann <[email protected]>
+
+ * gpgme.m4: Implement the --api-version check.
+
+ * rungpg.c (read_status): Move the polling of the output data pipe
+ to just before removing the command fd, from just before adding
+ it. This avoids buffering problems.
+
+ * data.c (_gpgme_data_inbound_handler): Use _gpgme_io_read, not
+ read, to improve debug output.
+
+2004-09-29 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (GPGME_IMPORT_NEW, GPGME_IMPORT_UID, GPGME_IMPORT_SIG,
+ GPGME_IMPORT_SUBKEY, GPGME_IMPORT_SECRET,
+ (GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODERN_EXTERN,
+ GPGME_KEYLIST_MODE_SIGS, GPGME_KEYLIST_MODE_VALIDATE): Change from
+ enum to macros.
+ (gpgme_keylist_mode_t): Define as unsigned int.
+ (gpgme_key_t): Change type of keylist_mode to
+ gpgme_keylist_mode_t.
+
+2004-09-23 Marcus Brinkmann <[email protected]>
+
+ * data.c (_gpgme_data_outbound_handler): Close the file descriptor
+ if we get an EPIPE.
+
+ * data-stream.c (stream_seek): Call ftello and return the current
+ offset.
+ * data.h (struct gpgme_data): Change type of data.mem.offset to
+ off_t.
+ * data.c (gpgme_data_seek): Check dh->cbs->seek callback, not read
+ callback. If SEEK_CUR, adjust the offset by the pending buffer
+ size. Clear pending buffer on success.
+
+
+2004-09-14 Marcus Brinkmann <[email protected]>
+
+ * gpgme.m4: Add copyright notice.
+
+2004-08-18 Marcus Brinkmann <[email protected]>
+
+ * passphrase.c (_gpgme_passphrase_status_handler): Always run the
+ status handler.
+
+2004-08-17 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (build_argv): Use --no-sk-comment, not --no-comment.
+
+2004-06-23 Marcus Brinkmann <[email protected]>
+
+ * key.c (_gpgme_key_append_name): Make sure tail points to the
+ byte following the uid.
+ (_gpgme_key_add_sig): Likewise. Don't use calloc, but malloc and
+ memset.
+
+2004-06-02 Marcus Brinkmann <[email protected]>
+
+ * libgpgme.vers: Remove C-style comment, which is not supported by
+ older binutils.
+
+2004-05-21 Marcus Brinkmann <[email protected]>
+
+ * gpgme-config.in (Options): Support --api-version.
+
+ * libgpgme.vers: List all gpgme symbols under version GPGME_1.0.
+
+ * decrypt.c (_gpgme_decrypt_status_handler): Fix last change.
+ * verify.c (parse_error): Likewise.
+
+ * verify.c (parse_error): Do not skip location of where token.
+
+ * gpgme.h (gpgme_status_code_t): Add GPGME_STATUS_REVKEYSIG.
+ * verify.c (_gpgme_verify_status_handler): Add handling of
+ GPGME_STATUS_REVKEYSIG.
+ (parse_trust): Likewise.
+
+2004-05-21 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_decrypt_result): New fields
+ wrong_key_usage and _unused.
+ * decrypt.c (_gpgme_decrypt_status_handler): Don't skip over
+ character after a matched string, as in a protocol error this
+ could skip over the trailing binary zero.
+ Handle decrypt.keyusage error notifications.
+
+ * gpgme.h (struct _gpgme_key): New member keylist_mode.
+ * keylist.c (keylist_colon_handler): Set the keylist_mode of KEY.
+
+2004-04-29 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_signature): Change member WRONG_KEY_USAGE
+ to unsigned int. Same for member _unused.
+
+ * keylist.c (set_mainkey_trust_info): Rewritten.
+ (set_subkey_capability): Handle 'd' (disabled).
+ (set_mainkey_capability): Rewritten.
+
+2004-04-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.m4: Quote first argument to AC_DEFUN.
+
+2004-04-21 Werner Koch <[email protected]>
+
+ * key.c (gpgme_key_unref): Allow passing NULL like free does.
+ The rule of least surprise.
+
+2004-04-15 Werner Koch <[email protected]>
+
+ * verify.c (prepare_new_sig, _gpgme_verify_status_handler): Remove
+ unused result.signatures items.
+
+ * keylist.c (gpgme_get_key): Return an error if FPR is NULL.
+
+2004-04-08 Werner Koch <[email protected]>
+
+ * verify.c (_gpgme_verify_status_handler): Ignore the error status
+ if we can't process it.
+ * decrypt-verify.c (decrypt_verify_status_handler): Backed out
+ yesterday's hack. It is not any longer required.
+
+2004-04-07 Werner Koch <[email protected]>
+
+ * decrypt-verify.c (decrypt_verify_status_handler): Hack to cope
+ with meaningless error codes from the verify status function.
+
+2004-04-05 Werner Koch <[email protected]>
+
+ * gpgme.h: Add GPGME_STATUS_NEWSIG.
+
+ * verify.c (parse_error): Compare only the last part of the where
+ token.
+ (prepare_new_sig): New.
+ (parse_new_sig): Use prepare_new_sig when required.
+ (_gpgme_verify_status_handler): Handle STATUS_NEWSIG.
+
+ * engine-gpgsm.c (gpgsm_keylist_ext): Send with-validation
+ option. Fixed pattern construction.
+ (status_handler): Add debugging output.
+
+2004-03-23 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_new): Protect _only_ tty related code with
+ isatty(). Submitted by Bernhard Herzog.
+
+2004-03-11 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_new): Protect all tty related code with
+ isatty().
+
+ * rungpg.c (gpg_cancel): Set GPG->fd_data_map to NULL after
+ releasing it.
+ * engine-gpgsm.c (gpgsm_cancel): Only call assuan_disconnect if
+ GPGSM->assuan_ctx is not NULL. Set it to NULL afterwards.
+
+2004-03-07 Marcus Brinkmann <[email protected]>
+
+ * gpgme-config.in: Do not emit include and lib directory for
+ prefix "/usr" or "".
+
+2004-03-03 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_export_ext): Properly insert a space
+ beween patterns.
+
+2004-02-18 Werner Koch <[email protected]>
+
+ * gpgme-config.in: Ignore setting of --prefix.
+
+2004-02-25 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (gpg_cancel): New function.
+ (gpg_release): Call it here.
+ (_gpgme_engine_ops_gpg): Add it here.
+ * engine-gpgsm.c (gpgsm_cancel): Fix last change.
+
+2004-02-24 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_cancel): New function.
+ * engine-backend.h (struct engine_ops): New member cancel.
+ * engine.h (_gpgme_engine_cancel): New prototype.
+ * engine.c (_gpgme_engine_cancel): New function.
+ * engine-gpgsm.c (_gpgme_engine_ops_gpgsm): Add new member cancel.
+ (gpgsm_cancel): New function.
+ (gpgsm_release): Use it.
+ * rungpg.c (_gpgme_engine_ops_gpg): Add new member cancel.
+
+2004-02-17 Werner Koch <[email protected]>
+
+ * gpgme.h: Add GPGME_KEYLIST_MODE_VALIDATE.
+ * engine-gpgsm.c (gpgsm_keylist): Send this to gpgsm.
+
+2004-02-15 Werner Koch <[email protected]>
+
+ * memrchr.c (memrchr): Fixed implementation. Problem pointed out
+ by Adriaan de Groot.
+
+2004-02-01 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (build_argv): Use --no-comment, not --comment "".
+
+ * data-compat.c (gpgme_data_new_from_filepart): Call fseeko if
+ available.
+ * data-stream.c (stream_seek): Likewise.
+
+2004-01-16 Werner Koch <[email protected]>
+
+ * conversion.c (_gpgme_map_gnupg_error): Handle numerical codes as
+ used by GnuPG 1.9.x
+
+2004-01-13 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_key_sig): Fix comment on REVOKED.
+
+2004-01-12 Werner Koch <[email protected]>
+
+ * sign.c: Include util.h for prototype of _gpgme_parse_timestamp.
+
+2003-12-25 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (_GPGME_D_CLASS): Revert this change.
+ (struct _gpgme_key_sig): For C++ compilers, rename class
+ member to _obsolete_class. Add new member sig_class.
+ (struct _gpgme_new_signature): Same here.
+ * key.c (gpgme_key_sig_get_ulong_attr): Use CERTSIG->sig_class,
+ not CERTSIG->class.
+ * keylist.c (keylist_colon_handler): Likewise for KEYSIG, but keep
+ setting KEYSIG->class, too. Rename variable CLASS to SIG_CLASS.
+ * sign.c (parse_sig_created): Set SIG->sig_class.
+
+2003-12-22 Werner Koch <[email protected]>
+
+ * gpgme.h (_GPGME_D_CLASS): Kludge for C++ compatibility without
+ changing the C API.
+
+2003-11-19 Werner Koch <[email protected]>
+
+ * conversion.c (_gpgme_parse_timestamp): New.
+ (atoi_1, atoi_2, atoi_4): New.
+ * keylist.c (parse_timestamp): Removed. Changed all callers to use
+ the new function.
+ * verify.c (parse_valid_sig): Ditto. Repalced the errno check.
+ * sign.c (parse_sig_created): Ditto.
+
+2003-10-31 Werner Koch <[email protected]>
+
+ * keylist.c (parse_timestamp): Detect ISO 8601 timestamps and try
+ to convert them.
+
+2003-10-10 Marcus Brinkmann <[email protected]>
+
+ * genkey.c (get_key_parameter): Make a copy of the key parameters.
+ Submitted by Miguel Coca <[email protected]>.
+
+2003-10-06 Marcus Brinkmann <[email protected]>
+
+ * data-compat.c: Include <sys/time.h> before <sys/stat.h> for
+ broken systems.
+
+ * engine-gpgsm.c (map_assuan_error): If ERR is -1, return sensible
+ error.
+
+ * io.h (_gpgme_io_subsystem_init): New prototype.
+ * posix-io.c (_gpgme_io_subsystem_init): Add function.
+ (_gpgme_io_spawn): Do not fixup signal handler here.
+ * version.c (do_subsystem_inits): Call _gpgme_io_subsystem_init.
+
+ * debug.c (debug_init): Drop const qualifier from E.
+
+ * ath.h (struct ath_ops): Make ADDR argument of CONNECT prototype
+ const.
+ (ath_connect): Make ADDR argument const.
+ * ath-pthread.c (ath_connect): Likewise.
+ * ath-pth.c (ath_connect): Likewise.
+ * ath-compat.c (ath_connect): Likewise.
+ * ath.c (ath_connect): Likewise.
+
+ * ath.h [HAVE_SYS_SELECT_H]: Include <sys/select.h> for fd_set.
+ [!HAVE_SYS_SELECT_H]: Include <sys/time.h>.
+
+ * conversion.c (_gpgme_hextobyte): Drop "unsigned" from type of
+ SRC argument.
+ * util.h (_gpgme_hextobyte): Likewise for prototype.
+
+ * gpgme.h: Remove trailing comma in enum.
+
+ * rungpg.c: Do not include <time.h>, <sys/time.h>, <sys/types.h>,
+ <signal.h>, <fcntl.h>, or "unistd.h".
+
+2003-10-02 Marcus Brinkmann <[email protected]>
+
+ * engine-backend.h (struct engine_ops): Add argument TYPE.
+ * engine.c (_gpgme_engine_op_edit): Likewise.
+ * engine.h: Likewise.
+ * rungpg.c (gpg_edit): Likewise. Use it.
+ * edit.c (edit_start): Likewise. Pass it on.
+ (gpgme_op_edit_start, gpgme_op_edit): Likewise.
+ (gpgme_op_card_edit_start, gpgme_op_card_edit): New functions.
+
+2003-09-30 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpg_strerror_r): Change prototype to match
+ gpg_strerror_r change.
+ * error.c (gpg_strerror_r): Likewise, also update implementation.
+
+ * gpgme.c (gpgme_hash_algo_name): Change name of RMD160 to
+ RIPEMD160, name of TIGER to TIGER192, name of CRC32-RFC1510 to
+ CRC32RFC1510, and name of CRC24-RFC2440 to CRC24RFC2440.
+
+2003-09-14 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add prototype for gpgme_set_locale.
+
+ * gpgme.h: Define macro _GPGME_INLINE depending on the compiler
+ characteristics and use that instead __inline__.
+
+ * context.h (struct gpgme_context): New members lc_ctype and
+ lc_messages.
+ * gpgme.c: Include <locale.h>.
+ (def_lc_lock, def_lc_ctype, def_lc_messages): New static
+ variables.
+ (gpgme_set_locale): New function.
+ * engine.c (_gpgme_engine_new): Add arguments lc_ctype and
+ lc_messages.
+ * engine.h (_gpgme_engine_new): Likewise.
+ * engine-gpgsm.c (gpgsm_new): Likewise.
+ * rungpg.c (gpg_new): Likewise.
+ * engine-backend.h (struct engine_ops): Likewise to NEW.
+ * op-support.c (_gpgme_op_reset): Likewise to invocation of
+ _gpgme_engine_new.
+
+2003-09-13 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_strerror_r): New prototype.
+ * error.c (gpgme_strerror_r): New function.
+
+ * get-env.c: New file.
+ * util.h (_gpgme_getenv): Add prototype.
+ * Makefile.am (libgpgme_real_la_SOURCES): Add get-env.c.
+ * rungpg.c (build_argv): Use _gpgme_getenv.
+ * debug.c (debug_init): Likewise.
+ * engine-gpgsm.c (gpgsm_new): Likewise.
+ (gpgsm_new): Use ttyname_r.
+ * w32-io.c (_gpgme_io_spawn): Disable debugging for now.
+
+2003-09-03 Marcus Brinkmann <[email protected]>
+
+ * gpgme-config.in: Use $libdir, not @libdir@, for the echo
+ command.
+
+ * gpgme-config.in: Rewritten.
+ * gpgme.m4: Rewritten.
+
+2003-08-19 Marcus Brinkmann <[email protected]>
+
+ The ath files (ath.h, ath.c, ath-pth.c, ath-pthread.c,
+ ath-compat.c, ath-pth-compat.c and ath-pthread-compat.c) have been
+ updated to have better thread support, and the Makefile.am was
+ changed to reflect that.
+
+ * util.h [!HAVE_FOPENCOOKIE]: Remove fopencookie declaration.
+ * engine-gpgsm.c (gpgsm_assuan_simple_command): Set ERR to return
+ value of status_fnc.
+ * rungpg.c (start): Return SAVED_ERRNO, not errno.
+
+2003-08-18 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (start): Use saved_errno instead errno.
+
+2003-08-18 Marcus Brinkmann <[email protected]>
+
+ * funopen.c, putc_unlocked.c, isascii.c, memrchr.c: New files.
+ * fopencookie.c: File removed.
+
+2003-08-15 Marcus Brinkmann <[email protected]>
+
+ * gpgme-config.in: Put gpg-error related flags after gpgme's.
+
+2003-08-14 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_new_signature): Rename member CLASS to
+ _OBSOLETE_CLASS, add member CLASS with type unsigned int.
+ * sign.c (parse_sig_created): Also set SIG->_unused_class for
+ backward compatibility.
+
+2003-08-04 Marcus Brinkmann <[email protected]>
+
+ * verify.c (parse_new_sig): Fix status parsing case.
+
+2003-07-31 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_subkey): Add flag CAN_AUTHENTICATE.
+ Lower _UNUSED to 23 bits.
+ (struct _gpgme_key): Likewise.
+ * keylist.c (set_mainkey_capability): Support 'a' and 'A'.
+ (set_subkey_capability): Support 'a'.
+
+ * keylist.c (gpgme_get_key): Check if there is more than one key
+ listed, and return GPG_ERR_AMBIGUOUS_NAME in that case.
+
+ * util.h (_gpgme_decode_c_string): Change type of LEN argument to
+ size_t.
+ (_gpgme_decode_percent_string): Likewise.
+ * conversion.c (_gpgme_decode_c_string): Likewise.
+ (_gpgme_decode_percent_string): Likewise.
+ (_gpgme_map_gnupg_error): Change type of I to unsigned int.
+ * signers.c (gpgme_signers_clear): Likewise.
+ (gpgme_signers_enum): New unsigned variable SEQNO, set to SEQ.
+ Use SEQNO instead SEQ.
+ * wait.c (fd_table_put): Change type of I and J to unsigned int.
+ * wait-global.c (_gpgme_wait_global_event_cb): Change type of IDX
+ to unsigned int.
+ (gpgme_wait): Change type of I and IDX to unsigned int.
+ * wait-private.c (_gpgme_wait_on_condition): Change type of IDX
+ and I to unsigned int.
+ * posix-io.c (_gpgme_io_close): Cast return value of macro DIM to
+ int to suppress gcc warning.
+ (_gpgme_io_set_close_notify): Likewise.
+ (_gpgme_io_select): Change type of I to unsigned int.
+ * engine.c (gpgme_get_engine_info): Change type of PROTO to
+ unsigned int.
+ * wait-user.c (_gpgme_user_io_cb_handler): Change type of IDX and
+ I to unsigned int.
+
+2003-07-29 Marcus Brinkmann <[email protected]>
+
+ * decrypt-verify.c (decrypt_verify_status_handler): Expand silly
+ and wrong expression.
+ * encrypt-sign.c (encrypt_sign_status_handler): Likewise.
+ * encrypt.c (encrypt_sym_status_handler): Likewise.
+ * sign.c (sign_status_handler): Likewise.
+ * verify.c (verify_status_handler): Likewise.
+ * decrypt.c (decrypt_status_handler): Likewise.
+
+ * engine.c (gpgme_get_engine_info): Initialize NULL.
+
+2003-07-23 Marcus Brinkmann <[email protected]>
+
+ * gpgme-config.in (gpg_error_libs): Quote GPG_ERROR_CFLAGS and
+ GPG_ERROR_LIBS when setting the corresponding variables.
+ Reported by St�phane Corth�sy.
+
+2003-07-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (set_recipients): Move declaration of NEWLEN to
+ the beginning of the block.
+
+2003-06-22 Marcus Brinkmann <[email protected]>
+
+ * data-mem.c (mem_write): Copy original buffer content.
+
+2003-06-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_user_ids_release, gpgme_user_ids_append): Remove
+ prototypes.
+
+2003-06-06 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (AM_CPPFLAGS): Add @GPG_ERROR_CFLAGS@.
+ * gpgme-config.in (gpg_error_libs, gpg_error_cflags): New variables.
+ Print them.
+
+ * op-support.c (_gpgme_parse_inv_userid): Rename to
+ _gpgme_parse_inv_recp and change to new datatype.
+ * ops.h (_gpgme_parse_inv_key): Fix prototype.
+ * gpgme.h (struct _gpgme_invalid_user_id): Rename to
+ __gpgme_invalid_key. Rename field ID to KEY.
+ (gpgme_invalid_user_id_t): Rename to gpgme_invalid_key_t.
+ (struct _gpgme_op_encrypt_result): Here, too.
+ (struct _gpgme_op_sign_result): Likewise.
+ * encrypt.c (struct op_data): Likewise.
+ (release_op_data): Likewise.
+ * sign.c (struct op_data): Likewise.
+ (release_op_data): Likewise.
+
+ * posix-io.c (_gpgme_io_read): Save errno across debug calls.
+ (_gpgme_io_write): Likewise.
+ (_gpgme_io_pipe): Likewise.
+ (_gpgme_io_select): Likewise.
+
+ * rungpg.c (struct engine_gpg): Remove arg_error.
+ (add_arg): Don't set arg_error.
+ (add_data): Likewise.
+ (start): Don't check arg_error.
+ (gpg_new): Check return value of add_arg.
+ * verify.c (parse_notation): Free allocated memory at error.
+
+2003-06-05 Marcus Brinkmann <[email protected]>
+
+ Everywhere: Use libgpg-error error codes.
+
+ * Makefile.am (EXTRA_DIST): Remove mkerrors.
+ (BUILT_SOURCES): Remove errors.c.
+ (MOSTLYCLEANFILES): Likewise.
+ (libgpgme_la_SOURCES): Likewise. Add error.c.
+ (errors.c): Remove target.
+ * mkerrors: File removed.
+ * error.c: New file.
+
+ * gpgme.h (gpgme_error_t): Change to type gpg_error_t.
+ (gpgme_err_code_t, gpgme_err_source_t): New types.
+ (gpgme_err_code, gpgme_err_source, gpgme_error, gpgme_err_make):
+ New static inline functions.
+ (gpgme_strsource, gpgme_err_code_from_errno,
+ gpgme_err_code_to_errno, gpgme_err_make_from_errno,
+ gpgme_error_from_errno): New prototypes.
+
+2003-05-29 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_op_export_start): Change second arg to const char *.
+ (gpgme_op_export): Likewise.
+ (gpgme_op_export_ext_start): New prototype.
+ (gpgme_op_export_ext): Likewise.
+ * engine.h: Likewise for _gpgme_engine_op_export and
+ _gpgme_engine_op_export_ext.
+ * engine-backend.h (struct engine_ops): Change second argument of
+ prototype of export to const char *, and add reserverd int as
+ third argument. Add prototype for export_ext.
+ * engine.c (_gpgme_engine_op_export_ext): New function.
+ (_gpgme_engine_op_export): Change second argument of prototype of
+ export to const char *, and add reserverd int as third argument.
+ * rungpg.c (gpg_export): Change second argument of prototype of
+ export to const char *, and add reserverd int as third argument.
+ (gpg_export_ext): New function.
+ (gpg_keylist_ext): Break loop at error.
+ (_gpgme_engine_ops_gpg): Add gpg_export_ext.
+ * engine-gpgsm.c (gpgsm_export): Change second argument of
+ prototype of export to const char *, and add reserverd int as
+ third argument.
+ (gpgsm_export_ext): New function.
+ (_gpgme_engine_ops_gpgsm): Add gpgsm_export_ext.
+ * export.c (export_start): Change second argument of prototype of
+ export to const char *, and add reserverd int as third argument.
+ (gpgme_op_export_start): Likewise.
+ (export_ext_start): New function.
+ (gpgme_op_export_ext_start): Likewise.
+ (gpgme_op_export_ext): Likewise.
+
+ * gpgme.h (gpgme_keylist_mode_t): New type for anonymous enum.
+ (gpgme_sigsum_t): New type for anonymous enum.
+
+ * encrypt-sign.c (encrypt_sign_start): Check for errors earlier,
+ and return an error if RECP is not set.
+
+ * Makefile.am (libgpgme_la_SOURCES): Remove user-id.c.
+ * user-id.c: Remove file.
+ * ops.h: Remove prototype for _gpgme_user_ids_all_valid.
+ * gpgme.h (gpgme_encrypt_flags_t): New type.
+ (gpgme_op_encrypt_start): Change second parameter to type
+ gpgme_key_t[], and add third parameter.
+ (gpgme_op_encrypt): Likewise.
+ (gpgme_op_encrypt_sign_start): Likewise.
+ (gpgme_op_encrypt_sign): Likewise.
+ * encrypt.c (encrypt_start): Likewise.
+ (gpgme_op_encrypt_start): Likewise.
+ (gpgme_op_encrypt): Likewise. Pass flags to engine.
+ * encrypt-sign.c (encrypt_sign_start): Likewise.
+ (gpgme_op_encrypt_sign_start): Likewise.
+ (gpgme_op_encrypt_sign): Likewise.
+ * engine-backend.h (struct engine_ops): Likewise for prototypes of
+ encrypt and encrypt_sign.
+ * engine.h: Likewise for prototypes of _gpgme_engine_op_encrypt
+ and _gpgme_engine_op_encrypt_sign.
+ * engine.c (_gpgme_engine_op_encrypt): Likewise.
+ (_gpgme_engine_op_encrypt_sign): Likewise.
+ * rungpg.c (gpg_encrypt): Likewise.
+ (gpg_encrypt_sign): Likewise.
+ * rungpg.c (gpg_encrypt): Check flags for always trust option.
+ * engine-gpgsm.c (gpgsm_encrypt): Likewise.
+ (set_recipients): Rewritten to use keys instead user IDs.
+ * rungpg.c (append_args_from_recipients): Rewritten to use keys
+ instead user IDs.
+ * encrypt.c (_gpgme_encrypt_status_handler): Change errors
+ returned to GPGME_Invalid_Key and GPGME_General_Error.
+
+2003-05-28 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c: Rename GpgsmObject to engine_gpgsm_t.
+ (struct gpgsm_object_s): Rename to struct engine_gpgsm.
+ * rungpg.c: Rename GpgObject to engine_gpg_t.
+ (struct gpg_object_s): Rename to struct engine_gpg.
+
+ * context.h (struct gpgme_context): Change EngineObject to
+ engine_object_t.
+ (enum ctx_op_data_type): Rename to ctx_op_data_id_t.
+ (ctx_op_data_t): New type.
+ (struct gpgme_context): Use it.
+ * ops.h (_gpgme_op_data_lookup): Use new type name.
+ * op-support.c (_gpgme_op_data_lookup): Likewise.
+ * engine.c: Rename EngineObject to engine_t in the file. Also
+ EngineStatusHandler to engine_status_handler_t,
+ EngineCommandHandler to engine_command_handler_t and
+ EngineColonLineHandler to engine_colon_line_handler.
+ * rungpg.c (start): Likewise.
+ * engine-gpgsm.c: Likewise.
+ * engine-backend.h (struct engine_ops): Likewise
+ * engine.h (struct engine_object_s): Rename to struct engine.
+ (EngineObject): Rename to engine_t. Also everywhere else in the
+ file.
+ (EngineStatusHandler): Rename to engine_status_handler_t.
+ (EngineColonLineHandler): Rename to engine_colon_line_handler_t.
+ (EngineCommandHandler): Rename to engine_command_handler_t.
+
+ * engine-gpgsm.c (gpgsm_export): Fix bug in last change.
+
+ * Makefile.am (libgpgme_la_SOURCES): Remove recipient.c, add
+ user-id.c.
+ * gpgme.h (gpgme_recipients_t): Removed.
+ (gpgme_recipients_new, gpgme_recipients_release,
+ gpgme_recipients_add_name,
+ gpgme_recipients_add_name_with_validity, gpgme_recipients_count,
+ gpgme_recipients_enum_open, gpgme_recipients_enum_read,
+ gpgme_recipients_enum_close): Removed.
+ (gpgme_op_encrypt, gpgme_op_encrypt_start, gpgme_op_encrypt_sign,
+ gpgme_op_encrypt_sign_start, gpgme_op_export_start,
+ gpgme_op_export): Change second argument to gpgme_user_id_t.
+ (gpgme_user_ids_release): New prototype.
+ (gpgme_user_ids_append): Likewise.
+ * ops.h (_gpgme_recipients_all_valid): Remove.
+ (_gpgme_user_ids_all_valid): Add.
+ * context.h (struct gpgme_recipients): Removed.
+ * user-id.c: New file.
+ * recipient.c: Removed file.
+ * rungpg.c (append_args_from_recipients): Change last arg to
+ gpgme_user_id_t. Reimplement.
+ (gpg_encrypt): Change second arg to gpgme_user_id_t.
+ (gpg_encrypt_sign): Likewise.
+ (gpg_export): Likewise. Rewrite user ID list code.
+ * engine.c (_gpgme_engine_op_encrypt): Change second arg to
+ gpgme_user_id_t.
+ (_gpgme_engine_op_encrypt_sign): Likewise.
+ (_gpgme_engine_op_export): Likewise.
+ * engine.h (_gpgme_engine_op_encrypt, _gpgme_engine_op_encrypt_sign,
+ _gpgme_engine_op_export): Likewise.
+ * engine-gpgsm.c (set_recipients): Likewise. Rewrite loop code.
+ (gpgsm_encrypt): Likewise.
+ (gpgsm_export): Likewise.
+ * engine-backend.h (struct engine_ops): Likewise for members
+ ENCRYPT, ENCRYPT_SIGN and EXPORT.
+ * export.c (export_start, gpgme_op_export_start, gpgme_op_export):
+ Likewise.
+ * encrypt.c (encrypt_start): Likewise. Don't check for count of
+ recipients.
+ (gpgme_op_encrypt_start): Likewise.
+ (gpgme_op_encrypt): Likewise.
+ * encrypt-sign.c (encrypt_sign_start): Likewise.
+ (gpgme_op_encrypt_sign): Likewise.
+ (gpgme_op_encrypt_sign_start): Likewise.
+
+2003-05-27 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_op_import_result): Add skipped_new_keys.
+ * import.c (parse_import_res): Add skipped_new_keys parser.
+
+ * op-support.c (_gpgme_parse_inv_userid): Add missing break
+ statements.
+ * encrypt.c (gpgme_op_encrypt): Use gpgme_error_t instead of int.
+
+2003-05-27 Marcus Brinkmann <[email protected]>
+
+ * encrypt.c (gpgme_op_encrypt_result): Use intermediate variable
+ HOOK to avoid compiler warning. Don't ask, you don't want to know.
+ (_gpgme_encrypt_status_handler): Likewise.
+ (_gpgme_op_encrypt_init_result): Likewise.
+ * decrypt.c (gpgme_op_decrypt_result): Likewise.
+ (_gpgme_decrypt_status_handler): Likewise.
+ (_gpgme_op_decrypt_init_result): Likewise.
+ * verify.c (gpgme_op_verify_result): Likewise.
+ (_gpgme_verify_status_handler): Likewise.
+ (_gpgme_op_verify_init_result): Likewise.
+ * edit.c (edit_status_handler): Likewise.
+ (command_handler): Likewise.
+ (edit_start): Likewise.
+ * genkey.c (gpgme_op_genkey_result): Likewise.
+ (genkey_status_handler): Likewise.
+ (genkey_start): Likewise.
+ * import.c (gpgme_op_import_result): Likewise.
+ (import_status_handler): Likewise.
+ (_gpgme_op_import_start): Likewise.
+ * trustlist.c (gpgme_op_trustlist_next): Likewise.
+ (_gpgme_op_trustlist_event_cb): Likewise.
+ (gpgme_op_trustlist_start): Likewise.
+ * keylist.c (gpgme_op_keylist_result): Likewise.
+ (keylist_colon_handler): Likewise.
+ (keylist_status_handler): Likewise.
+ (_gpgme_op_keylist_event_cb): Likewise.
+ (gpgme_op_keylist_start): Likewise.
+ (gpgme_op_keylist_ext_start): Likewise.
+ (gpgme_op_keylist_next): Likewise.
+ * passphrase.c (_gpgme_passphrase_status_handler): Likewise.
+ (_gpgme_passphrase_command_handler_internal): Likewise.
+ * sign.c (gpgme_op_sign_result): Likewise.
+ (_gpgme_sign_status_handler): Likewise.
+ (_gpgme_op_sign_init_result): Likewise.
+
+ * passphrase.c (_gpgme_passphrase_command_handler_internal): Fix
+ access to pointer type.
+
+2003-05-26 Marcus Brinkmann <[email protected]>
+
+ * engine.h (EngineCommandHandler): Change last argument to int fd.
+ * gpgme.h (gpgme_passphrase_cb_t): Rewritten to take parts of the
+ description and fd.
+ (gpgme_edit_cb_t): Change last argument to int fd.
+ * ops.h (_gpgme_passphrase_command_handler_internal): New prototype.
+ * passphrase.c: Include <assert.h>.
+ (op_data_t): Rename userid_hint to uid_hint, remove last_pw_handle.
+ (release_op_data): Check values before calling free.
+ (_gpgme_passphrase_status_handler): Likewise.
+ (_gpgme_passphrase_command_handler_internal): New function.
+ (_gpgme_passphrase_command_handler): Rewritten.
+ * edit.c (edit_status_handler): Pass -1 as fd argument.
+ (command_handler): Update prototype. New variable processed. Use
+ it to store return value of
+ _gpgme_passphrase_command_handler_internal which is now used
+ instead _gpgme_passphrase_command_handler. Use it also to check
+ if we should call the user's edit function. Pass fd to user's
+ edit function.
+ * rungpg.c (struct gpg_object_s): Change type of cmd.cb_data to
+ void *.
+ (gpg_release): Check value before calling free. Do not release
+ cmd.cb_data.
+ (command_cb): Function removed.
+ (command_handler): New function. Thus we don't use a data object
+ for command handler stuff anymore, but handle it directly. This
+ allows proper error reporting (cancel of passphrase requests, for
+ example). Also all callbacks work via direct writes to the file
+ descriptor (so that passphrases are not kept in insecure memory).
+ (gpg_set_command_handler): Rewritten to use even more ugly hacks.
+ (read_status): Check cmd.keyword before calling free. Install
+ command_handler as the I/O callback handler with GPG as private
+ data.
+
+ * rungpg.c (gpg_new): Add --enable-progress-filter to gpg
+ invocation.
+ * decrypt-verify.c (_gpgme_op_decrypt_verify_start): Rename to
+ decrypt_verify_start.
+ (gpgme_op_decrypt_verify_start): Call decrypt_verify_start.
+ (gpgme_op_decrypt_verify): Likewise.
+ * verify.c (verify_status_handler): New function that also calls
+ progress status handler.
+ (_gpgme_op_verify_start): Set status handler to verify_status_handler.
+ Rename to (verify_start).
+ (gpgme_op_verify_start): Call verify_start.
+ (gpgme_op_verify): Likewise.
+ * encrypt.c (encrypt_status_handler): New function.
+ (_gpgme_encrypt_sym_status_handler): Call progress status handler.
+ Make static. Rename to encrypt_sym_status_handler.
+ (encrypt_start): Set status handler to encrypt_sym_status_handler
+ or encrypt_status_handler.
+ * sign.c (sign_status_handler): New function.
+ (sign_start): Set status handler to sign_status_handler.
+ * decrypt.c (decrypt_status_handler): New function that also calls
+ progress status handler.
+ (decrypt_start): Set status handler to decrypt_status_handler.
+ * encrypt-sign.c (encrypt_sign_status_handler): Likewise.
+ * decrypt-verify.c (decrypt_verify_status_handler): Call
+ _gpgme_progress_status_handler.
+
+ * conversion.c (_gpgme_decode_c_string): Add missing break
+ statement.
+
+ * recipient.c (gpgme_recipients_add_name_with_validity): Add one
+ to buffer to allocate.
+
+2003-05-19 Marcus Brinkmann <[email protected]>
+
+ * verify.c (parse_new_sig): Fix ERRSIG case.
+ Submitted by Benjamin Lee <[email protected]>.
+
+2003-05-18 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: The following types are renamed. The old name is kept
+ as a deprecated typedef.
+ (GpgmeCtx): Rename to gpgme_ctx_t.
+ (GpgmeData): Rename to gpgme_data_t.
+ (GpgmeRecipients): Rename to gpgme_recipients_t.
+ (GpgmeError): Rename to gpgme_error_t.
+ (GpgmeDataEncoding): Rename to gpgme_data_encoding_t.
+ (GpgmePubKeyAlgo): Rename to gpgme_pubkey_algo_t.
+ (GpgmeHashAlgo): Rename to gpgme_hash_algo_t.
+ (GpgmeSigStat): Rename to gpgme_sig_stat_t.
+ (GpgmeSigMode): Rename to gpgme_sig_mode_t.
+ (GpgmeAttr): Rename to gpgme_attr_t.
+ (GpgmeValidity): Rename to gpgme_validity_t.
+ (GpgmeProtocol): Rename to gpgme_protocol_t.
+ (GpgmeStatusCode): Rename to gpgme_status_code_t.
+ (GpgmeEngineInfo): Rename to gpgme_engine_info_t.
+ (GpgmeSubkey): Rename to gpgme_subkey_t.
+ (GpgmeKeySig): Rename to gpgme_keysig_t.
+ (GpgmeUserID): Rename to gpgme_user_id_t.
+ (GpgmePassphraseCb): Rename to gpgme_passphrase_cb_t.
+ (GpgmeProgressCb): Rename to gpgme_progress_cb_t.
+ (GpgmeEditCb): Rename to gpgme_edit_cb_t.
+ (GpgmeIOCb): Rename to gpgme_io_cb_t.
+ (GpgmeRegisterIOCb): Rename to gpgme_register_io_cb_t.
+ (GpgmeRemoveIOCb): Rename to gpgme_remove_io_cb_t.
+ (GpgmeEventIO): Rename to gpgme_event_io_t.
+ (GpgmeEventIOCb): Rename to gpgme_event_io_cb_t.
+ (GpgmeIOCbs): Rename to gpgme_io_cbs.
+ (gpgme_io_cbs_t): New type.
+ (GpgmeDataReadCb): Rename to gpgme_data_read_cb_t.
+ (GpgmeDataWriteCb): Rename to gpgme_data_write_cb_t.
+ (GpgmeDataSeekCb): Rename to gpgme_data_seek_cb_t.
+ (GpgmeDataReleaseCb): Rename to gpgme_data_release_cb_t.
+ (GpgmeDataCbs): Rename to gpgme_data_cbs.
+ (gpgme_data_cbs_t): New type.
+ (GpgmeInvalidUserID): Rename to gpgme_invalid_user_id_t.
+ (GpgmeEncryptResult): Rename to gpgme_encrypt_result_t.
+ (GpgmeDecryptResult): Rename to gpgme_decrypt_result_t.
+ (GpgmeNewSignature): Rename to gpgme_new_signature_t.
+ (GpgmeSignResult): Rename to gpgme_sign_result_t.
+ (GpgmeSigNotation): Rename to gpgme_sig_notation_t.
+ (GpgmeSignature): Rename to gpgme_signature_t.
+ (GpgmeVerifyResult): Rename to gpgme_verify_result_t.
+ (GpgmeImportStatus): Rename to gpgme_import_status_t.
+ (GpgmeImportResult): Rename to gpgme_import_result_t.
+ (GpgmeGenKeyResult): Rename to gpgme_genkey_result_t.
+ (GpgmeKeyListResult): Rename to gpgme_keylist_result_t.
+ (GpgmeTrustItem): Rename to gpgme_trust_item_t.
+ * gpgme.h (gpgme_deprecated_error_t): New type, swallowing macros
+ GPGME_No_Recipients, GPGME_Invalid_Recipient and
+ GPGME_No_Passphrase.
+ * data.h (struct gpgme_data_s): Rename to struct gpgme_data.
+ * context.h (struct gpgme_context_s): Rename to struct
+ gpgme_context.
+ (struct gpgme_recipients_s): Rename to gpgme_recipients.
+
+2003-05-18 Marcus Brinkmann <[email protected]>
+
+ * keylist.c (finish_key): Clear OPD->tmp_uid.
+
+2003-05-18 Marcus Brinkmann <[email protected]>
+
+ * verify.c (_gpgme_verify_status_handler): Return GPGME_No_Data
+ for NODATA status without signatures.
+
+2003-05-05 Marcus Brinkmann <[email protected]>
+
+ * key.c (_gpgme_key_append_name): Use decoded string to parse user id.
+ (_gpgme_key_add_sig): Likewise.
+
+2003-05-04 Marcus Brinkmann <[email protected]>
+
+ * context.h (struct gpgme_context_s): Remove member op_info.
+
+ * key.c (_gpgme_key_add_sig): Initialize SIG->uid.
+
+ * gpgme.h (GpgmeError): Add deprecated values for
+ GPGME_Invalid_Type and GPGME_Invalid_Mode.
+
+2003-04-30 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_get_op_info): Remove prototype.
+ * ops.h (_gpgme_set_op_info,
+ _gpgme_data_release_and_return_string, _gpgme_data_get_as_string,
+ _gpgme_data_append, _gpgme_data_append_string,
+ _gpgme_data_append_string_for_xml, _gpgme_data_append_for_xml,
+ _gpgme_data_append_percentstring_for_xml): Likewise.
+ (_gpgme_progress_status_handler): Change first arg to void *.
+ * progress.c (_gpgme_progress_status_handler): Likewise.
+ * conversion.c: Do not include <string.h>, <errno.h>, <ctype.h>,
+ and <sys/types.h>, but <string.h>.
+ (_gpgme_data_append): Remove function.
+ (_gpgme_data_append_string): Likewise.
+ (_gpgme_data_append_for_xml): Likewise.
+ (_gpgme_data_append_string_for_xml): Likewise.
+ (_gpgme_data_append_percentstring_for_xml): Likewise.
+ * data-mem.c (_gpgme_data_get_as_string): Likewise.
+ (_gpgme_data_release_and_return_string): Likewise.
+ * gpgme.c (gpgme_get_op_info): Likewise.
+ (_gpgme_set_op_info): Likewise.
+
+ * gpgme.h (struct _gpgme_key): New structure.
+ (GpgmeKey): Define using _gpgme_key.
+ (struct _gpgme_subkey): New structure.
+ (GpgmeSubKey): New type.
+ (struct _gpgme_key_sig): New structure.
+ (GpgmeKeySig): New type.
+ (struct _gpgme_user_id): New structure.
+ (GpgmeUserID): New type.
+ (struct _gpgme_op_keylist_result): New structure.
+ (GpgmeKeyListResult): New type.
+ (gpgme_op_keylist_result): New function.
+ (gpgme_key_get_as_xml): Remove prototype.
+ * context.h (struct gpgme_context_s): Remove members tmp_key,
+ tmp_uid, key_cond and key_queue.
+ (struct key_queue_item_s): Remove structure.
+ (struct user_id_s): Remove structure.
+ (struct gpgme_recipients_s): Replace with simple
+ GpgmeUserID list.
+ * gpgme.c (gpgme_release): Do not release CTX->tmp_key.
+ * ops.h (_gpgme_key_add_subkey, _gpgme_key_append_name,
+ _gpgme_key_add_sig, _gpgme_trust_item_new): New prototypes.
+ * rungpg.c (command_cb): Return GpgmeError instead int.
+ New variable ERR. Use it to hold return value of cmd handler.
+ (gpg_delete): Access fingerprint of key directly.
+ (append_args_from_signers): Likewise.
+ (gpg_edit): Likewise.
+ (append_args_from_recipients): Use GpgmeUserID for recipient list.
+ * engine-gpgsm.c: Do not include "key.h".
+ (gpgsm_delete): Access fingerprint of key directly.
+ (gpgsm_sign): Likewise.
+ (set_recipients): Use GpgmeUserID for recipients. Invert invalid
+ user ID flag.
+ * key.h: File removed.
+ * key.c: Completely reworked to use exposed GpgmeKey data types.
+ * keylist.c: Likewise.
+ * recipient.c: Completely reworked to use GpgmeUserID.
+
+2003-04-29 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_get_key): Remove force_update argument.
+ * key-cache.c: File removed.
+ * Makefile.am (libgpgme_la_SOURCES): Remove key-cache.c.
+ * ops.h (_gpgme_key_cache_add, _gpgme_key_cache_get): Remove
+ prototypes.
+ * keylist.c (_gpgme_op_keylist_event_cb): Don't call
+ _gpgme_key_cache_add.
+ (gpgme_get_key): New function.
+ * verify.c (gpgme_get_sig_key): Remove last argument to
+ gpgme_get_key invocation.
+
+ * gpgme.h (struct _gpgme_trust_item): New structure.
+ (GpgmeTrustItem): New type.
+ (gpgme_trust_item_ref, gpgme_trust_item_unref): New prototypes.
+ * context.h (struct trust_queue_item_s): Remove structure.
+ (struct gpgme_context_s): Remove trust_queue member.
+ * Makefile.am (libgpgme_la_SOURCES): Add trust-item.c.
+ * trust-item.c: New file.
+ * trustlist.c: Do not include <stdio.h> or <time.h>, but
+ "gpgme.h".
+ (struct trust_queue_item_s): Change to new type op_data_t.
+ (trust_status_handler): Change first argument to void *.
+ (trust_colon_handler): Likewise.
+ (_gpgme_op_trustlist_event_cb): Use op_data_t type.
+ (gpgme_op_trustlist_start): Use op_data_t and rework error
+ handling.
+ (gpgme_op_trustlist_next): Use op_data_t.
+ (gpgme_trust_item_release): Remove function.
+ (gpgme_trust_item_get_string_attr): Likewise.
+ (gpgme_trust_item_get_int_attr): Likewise.
+
+ * verify.c (calc_sig_summary): Do not set GPGME_SIGSUM_SYS_ERROR
+ for bad signatures.
+
+2003-04-28 Marcus Brinkmann <[email protected]>
+
+ * context.h: Remove OPDATA_VERIFY_COLLECTING.
+ (struct gpgme_context_s): Remove member notation.
+ * gpgme.h: Make enum for GPGME_KEYLIST_MODE_* values.
+
+ * gpgme.h (struct _gpgme_sig_notation): New structure.
+ (GpgmeSigNotation): New type.
+ (struct _gpgme_signature): New structure.
+ (GpgmeSignature): New type.
+ (struct _gpgme_op_verify_result): New structure.
+ (GpgmeVerifyResult): New type.
+ (gpgme_op_verify_result): New prototype.
+ (gpgme_get_notation): Remove prototype.
+ * ops.h (_gpgme_op_verify_init_result): New prototype.
+ (_gpgme_verify_status_handler): Change first argument to void *.
+ * util.h (_gpgme_decode_percent_string, _gpgme_map_gnupg_error):
+ New prototypes.
+ * conversion.c (_gpgme_decode_percent_string): New function.
+ (gnupg_errors): New static global.
+ (_gpgme_map_gnupg_error): New function.
+ * gpgme.c (gpgme_release): Don't release CTX->notation.
+ (gpgme_get_notation): Remove function.
+ * decrypt-verify.c (_gpgme_op_decrypt_verify_start): Call
+ _gpgme_op_verify_init_result.
+ * verify.c: Do not include <stdio.h>, <assert.h> and "key.h", but
+ do include "gpgme.h".
+ (struct verify_result): Replace with ...
+ (op_data_t): ... this type.
+ (release_verify_result): Remove function.
+ (release_op_data): New function.
+ (is_token): Remove function.
+ (skip_token): Remove function.
+ (copy_token): Remove function.
+ (gpgme_op_verify_result): New function.
+ (calc_sig_summary): Rewritten.
+ (finish_sig): Remove function.
+ (parse_new_sig): New function.
+ (parse_valid_sig): New function.
+ (parse_notation): New function.
+ (parse_trust): New function.
+ (parse_error): New function.
+ (_gpgme_verify_status_handler): Rewritten. Change first argument
+ to void *.
+ (_gpgme_op_verify_start): Rework error handling. Call
+ _gpgme_op_verify_init_result.
+ (gpgme_op_verify): Do not release or clear CTX->notation.
+ (gpgme_get_sig_status): Rewritten.
+ (gpgme_get_sig_string_attr): Likewise.
+ (gpgme_get_sig_ulong_attr): Likewise.
+ (gpgme_get_sig_key): Likewise.
+
+ * gpgme.h (struct _gpgme_op_decrypt_result): New structure.
+ (GpgmeDecryptResult): New type.
+ (gpgme_op_decrypt_result): New prototype.
+ * ops.h (_gpgme_op_decrypt_init_result): New prototype.
+ (_gpgme_decrypt_status_handler): Fix prototype.
+ (_gpgme_decrypt_start): Remove prototype.
+ * decrypt-verify.c: Do not include <stdio.h>, <stdlib.h>,
+ <string.h> and <assert.h>, "util.h" and "context.h", but
+ "gpgme.h".
+ (decrypt_verify_status_handler): Change first argument to void *,
+ and rework error handling.
+ (_gpgme_op_decrypt_verify_start): New function.
+ (gpgme_op_decrypt_verify_start): Rewrite using
+ _gpgme_op_decrypt_verify_start.
+ (gpgme_op_decrypt_verify): Likewise.
+ * decrypt.c: Include <string.h>, "gpgme.h" and "util.h".
+ (struct decrypt_result): Change to typedef op_data_t, rewritten.
+ (is_token): Remove function.
+ (release_op_data): New function.
+ (skip_token): Remove function.
+ (gpgme_op_decrypt_result): New function.
+ (_gpgme_decrypt_status_handler): Change first argument to void *.
+ Rework error handling.
+ (_gpgme_decrypt_start): Rename to ...
+ (decrypt_start): ... this. Call _gpgme_op_decrypt_init_result.
+ (_gpgme_op_decrypt_init_result): New function.
+ (gpgme_op_decrypt_start): Use decrypt_start.
+ (gpgme_op_decrypt): Likewise.
+
+2003-04-27 Marcus Brinkmann <[email protected]>
+
+ * encrypt-sign.c: Do not include <stddef.h>, <stdio.h>,
+ <stdlib.h>, <string.h>, <assert.h> and "util.h", but "gpgme.h".
+ (_gpgme_op_encrypt_sign_start): Rename to ...
+ (encrypt_sign_start): ... this.
+ (gpgme_op_encrypt_sign_start): Use encrypt_sign_start, not
+ _gpgme_op_encrypt_sign_start.
+ (gpgme_op_encrypt_sign): Likewise.
+
+ * gpgme.h (GpgmeEncryptResult): New data type.
+ (gpgme_op_encrypt_result): New prototype.
+ * ops.h (_gpgme_op_encrypt_init_result): New prototype.
+ (_gpgme_op_encrypt_status_handler): Fix prototype.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Call
+ _gpgme_op_encrypt_init_result.
+ * encrypt.c: Do not include <stdio.h>, <assert.h>, "util.h" and
+ "wait.h". Include <errno.h> and "gpgme.h".
+ (SKIP_TOKEN_OR_RETURN): Remove macro.
+ (struct encrypt_result): Rename to ...
+ (op_data_t): ... new data type. Rewrite for user result data.
+ (append_xml_encinfo): Remove function.
+ (release_op_data): New function.
+ (gpgme_op_encrypt_result): New function.
+ (_gpgme_op_encrypt_status_handler): Change first argument to void *.
+ Rewrite result parsing.
+ (_gpgme_op_encrypt_sym_status_handler): Change first argument to
+ void *.
+ (_gpgme_op_encrypt_init_result): New function.
+ (_gpgme_op_encrypt_start): Rename to ...
+ (encrypt_start): ... this.
+ (gpgme_op_encrypt_start): Use encrypt_start, not
+ gpgme_op_encrypt_start.
+ (gpgme_op_encrypt): Likewise.
+
+ * gpgme.h (GpgmePubKeyAlgo, GpgmeHashAlgo, GpgmeInvalidUserID,
+ GpgmeNewSignature, GpgmeSignResult): New data types.
+ (gpgme_op_sign_result, gpgme_pubkey_algo_name,
+ gpgme_hash_algo_name): New prototypes.
+ * gpgme.c (gpgme_pubkey_algo_name): New function.
+ (gpgme_hash_algo_name): Likewise.
+ * ops.h (_gpgme_parse_inv_userid, _gpgme_op_sign_init_result): New
+ prototype.
+ (_gpgme_op_sign_status_handler): Fix prototype.
+ * op-support.c: Include <errno.h> and <string.h>.
+ (_gpgme_parse_inv_userid): New function.
+ * sign.c: Include <errno.h> and "gpgme.h", but not <stdio.h>,
+ <assert.h> and "util.h".
+ (SKIP_TOKEN_OR_RETURN): Remove macro.
+ (struct sign_result): Change to op_data_t type and rework it.
+ (release_sign_result): Rename to ...
+ (release_op_data): ... this and rewrite it.
+ (append_xml_info): Remove function.
+ (gpgme_op_sign_result): New function.
+ (parse_sig_created): New function.
+ (_gpgme_sign_status_handler): Change first argument to void *.
+ Rewrite the function to use the new result structure and functions.
+ (_gpgme_op_sign_init_result): New function.
+ (_gpgme_op_sign_start): Rename to ...
+ (sign_start): ... this. Call _gpgme_op_sign_init_result.
+ (gpgme_op_sign_start): Use sign_start instead _gpgme_op_sign_start.
+ (gpgme_op_sign): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Call
+ _gpgme_op_sign_init_result.
+
+ * delete.c: Include <errno.h> and "gpgme.h", but not "util.h" or
+ "key.h".
+ (enum delete_problem): Move into function delete_status_handler.
+ (delete_status_handler): Change first argument to void *. Parse
+ delete problem with strtol instead atoi. Return better error
+ values.
+ (_gpgme_op_delete_start): Rename to ...
+ (delete_start): ... this. Rework error handling.
+ (gpgme_op_delete_start): Use delete_start instead
+ _gpgme_op_delete_start.
+ (gpgme_op_delete): Likewise.
+ * gpgme.h (GpgmeDataType): Removed.
+
+2003-04-25 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Change GPGME_IMPORT_PRIVATE to GPGME_IMPORT_SECRET.
+ * import.c (parse_import_res): Parse unchanged field.
+
+ * gpgme.h: New enum for GPGME_IMPORT_NEW, GPGME_IMPORT_UID,
+ GPGME_IMPORT_SIG, GPGME_IMPORT_SUBKEY, GPGME_IMPORT_PRIVATE.
+ (GpgmeError): GPGME_Unknown_Reason, GPGME_Not_Found,
+ GPGME_Ambiguous_Specification, GPGME_Wrong_Key_Usage,
+ GPGME_Key_Revoked, GPGME_Key_Expired, GPGME_No_CRL_Known,
+ GPGME_CRL_Too_Old, GPGME_Policy_Mismatch, GPGME_No_Secret_Key,
+ GPGME_Key_Not_Trusted, GPGME_Issuer_Missing, GPGME_Chain_Too_Long,
+ GPGME_Unsupported_Algorithm, GPGME_Sig_Expired,
+ GPGME_Bad_Signature, GPGME_No_Public_Key added as new error codes.
+ (struct _gpgme_import_status): New structure.
+ (GpgmeImportStatus): New type.
+ (struct _gpgme_op_import_result): New structure.
+ (GpgmeImportResult): New type.
+ (gpgme_op_import_result): New function.
+ * import.c: Include <errno.h> and "gpgme.h", but not "util.h".
+ (struct import_result): Change to type op_data_t.
+ (release_import_result): Rename to ...
+ (release_op_data): ... this.
+ (append_xml_impinfo): Function removed.
+ (gpgme_op_import_result): New function.
+ (parse_import): New function.
+ (parse_import_res): Likewise.
+ (import_status_handler): Change first argument to void *. Rewrite
+ to use new functions.
+ (_gpgme_op_import_start): Rework error handling.
+
+ * edit.c: Do not include <assert.h>, "util.h", but "gpgme.h".
+ (edit_resut): Change to typedef for op_data_t.
+ (edit_status_handler): Change first argument to void *.
+ Rework error handling.
+ (command_handler): Rework error handling.
+ (_gpgme_op_edit_start): Rename to ...
+ (edit_start): ... this. Rework error handling.
+ (gpgme_op_edit_start): Rewrite using edit_start.
+ (gpgme_op_edit): Likewise.
+
+ * ops.h (_gpgme_passphrase_start): Remove prototype.
+ * passphrase.c: Do not include <assert.h>, "util.h" or
+ "debug.h", but "gpgme.h".
+ (struct passphrase_result): Change to typedef for op_data_t.
+ (release_passphrase_result): Rename to release_op_data.
+ (_gpgme_passphrase_status_handler): Change first argument to void *.
+ Use new op_data_t type.
+ (_gpgme_passphrase_command_handler): Use new op_data_t type.
+ (_gpgme_passphrase_start): Remove function.
+ * decrypt.c (_gpgme_decrypt_start): Rewrite error handling. Do
+ not call _gpgme_passphrase_start, but install command handler.
+ * encrypt.c (_gpgme_op_encrypt_start): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Likewise.
+ * sign.c (_gpgme_op_sign_start): Likewise.
+
+ * context.h (struct gpgme_context_s): Remove member initialized,
+ use_cms and help_data_1. Add member protocol. Make use_armor and
+ use_textmode bit flags. Make keylist_mode, include_certs,
+ signers_len and signers_size unsigned.
+ * gpgme.c (gpgme_new): Initialize CTX->protocol.
+ (gpgme_set_protocol): Do not check CTX. Use CTX->protocol.
+ (gpgme_get_protocol): Likewise.
+ (gpgme_release): Do not release CTX->help_data_1.
+ * op-support.c (_gpgme_op_reset): Use CTX->protocol.
+
+ * wait-private.c (_gpgme_wait_private_event_cb): Remove variable CTX.
+
+ * data.c: Do not include <assert.h>, but "gpgme.h".
+ (_gpgme_data_inbound_handler): Expand _gpgme_data_append, because
+ it will go. Do not assert DH.
+ (_gpgme_data_outbound_handler): Do not assert DH.
+
+ * export.c: Do not include <stdlib.h>, "debug.h" and "util.h", but
+ "gpgme.h".
+ (export_status_handler): Change type of first argument to void *.
+ (_gpgme_op_export_start): Rename to ...
+ (export_start): ... this. Rework error handling.
+ (gpgme_op_export_start): Rewritten to use export_start instead
+ _gpgme_op_export_start.
+ (gpgme_op_export): Likewise.
+
+ * gpgme.h (GpgmeError): Add GPGME_Busy, GPGME_No_Request.
+ (GPGME_No_Recipients, GPGME_Invalid_Recipient,
+ GPGME_No_Passphrase): New macros.
+
+ * key.c (gpgme_key_get_string_attr): Fix validity attribute.
+
+2003-04-24 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (struct _gpgme_op_genkey_result): New structure.
+ (GpgmeGenKeyResult): New type.
+ (gpgme_op_genkey): Drop last argument.
+ (gpgme_op_genkey_result): New function.
+ * genkey.c: Do not include "util.h", but "gpgme.h".
+ (struct genkey_result): Replace with ...
+ (op_data_t): ... this new type.
+ (release_genkey_result): Replace with ...
+ (release_op_data): ... this new function.
+ (gpgme_op_genkey_result): New function.
+ (genkey_status_handler): Rewritten using new op_data_t type.
+ (get_key_parameter): New function.
+ (_gpgme_op_genkey_start): Renamed to
+ (genkey_start): ... this and rewritten.
+ (gpgme_op_genkey_start): Use genkey_start instead
+ _gpgme_op_genkey_start.
+ (gpgme_op_genkey): Rewritten. Remove FPR argument.
+
+ * context.h (struct gpgme_context_s): Remove member verbosity.
+ * gpgme.c (gpgme_new): Do not set member verbosity.
+ * engine.h (_gpgme_engine_set_verbosity): Remove prototype.
+ * engine.c (_gpgme_engine_set_verbosity): Remove function.
+ * engine-backend.h (struct engine_ops): Remove set_verbosity.
+ * engine-gpgsm.c (_gpgme_engine_ops_gpgsm): Remove set_verbosity member.
+ * rungpg.c (_gpgme_engine_ops_gpg): Likewise.
+ (gpg_set_verbosity): Remove function.
+ * decrypt.c (_gpgme_decrypt_start): Don't call
+ _gpgme_engine_set_verbosity.
+ * delete.c (_gpgme_op_delete_start): Likewise.
+ * edit.c (_gpgme_op_edit_start): Likewise.
+ * encrypt.c (_gpgme_op_encrypt_start): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Likewise.
+ * export.c (_gpgme_op_export_start): Likewise.
+ * genkey.c (_gpgme_op_genkey_start): Likewise.
+ * import.c (_gpgme_op_import_start): Likewise.
+ * keylist.c (gpgme_op_keylist_start): Likewise.
+ (gpgme_op_keylist_ext_start): Likewise.
+ * sign.c (_gpgme_op_sign_start): Likewise.
+ * verify.c (_gpgme_op_verify_start): Likewise.
+
+ * Makefile.am (libgpgme_la_SOURCES): Add key-cache.c.
+ * key.c (key_cache_initialized, key_cache_size,
+ key_cache_max_chain_length, ): Removed.
+ (struct key_cache_item_s, key_cache_lock, key_cache,
+ key_cache_unused_items, hash_key, _gpgme_key_cache_add,
+ _gpgme_key_cache_get, gpgme_get_key): Moved to ...
+ * key-cache.c: ... here. New file.
+ * key.h (_gpgme_key_cache_init): Remove prototypes.
+ (_gpgme_key_cache_add,_gpgme_key_cache_get): Move to ...
+ * ops.h: ... here.
+ * version.c: Do not include "key.h".
+ (do_subsystem_inits): Do not call _gpgme_key_cache_init.
+
+ * mkstatus: Strip trailing comma.
+ * gpgme.h (GpgmeStatus): Pretty print.
+
+ * gpgme.h (GpgmeError): Rename GPGME_No_Passphrase to
+ GPGME_Bad_Passphrase.
+ * passphrase.c (_gpgme_passphrase_status_handler): Use
+ GPGME_Bad_Passphrase instead GPGME_No_Passphrase.
+
+ * gpgme.h (GpgmeError): Rename GPGME_No_Recipients to
+ GPGME_No_UserID and GPGME_Invalid_Recipient to
+ GPGME_Invalid_UserID.
+ * encrypt.c (_gpgme_encrypt_status_handler): Use GPGME_No_UserID
+ instead GPGME_No_Recipients and GPGME_Invalid_UserID instead
+ GPGME_Invalid_Recipient.
+ (_gpgme_op_encrypt_start): Likewise.
+
+ * gpgme.h (GpgmeError): Remove GPGME_Busy and GPGME_No_Request.
+ * wait-user.c (_gpgme_wait_user_event_cb): Don't clear CTX->pending.
+ * wait-private.c (_gpgme_wait_private_event_cb): Likewise.
+ * wait-global.c (gpgme_wait): Likewise.
+ * verify.c (_gpgme_op_verify_start): Likewise.
+ (gpgme_get_sig_status): Don't check pending flag.
+ (gpgme_get_sig_string_attr): Likewise.
+ (gpgme_get_sig_ulong_attr): Likewise.
+ (gpgme_get_sig_key): Likewise.
+ * op-support.c (_gpgme_op_reset): Likewise.
+ * trustlist.c (gpgme_op_trustlist_start): Don't clear pending flag.
+ (gpgme_op_trustlist_next): Don't check or clear pending flag.
+ (gpgme_op_trustlist_end): Likewise.
+ * sign.c (_gpgme_op_sign_start): Likewise.
+ * context.h (struct gpgme_context_s): Remove member PENDING.
+ * decrypt.c (_gpgme_decrypt_start): Likewise.
+ * delete.c (_gpgme_op_delete_start): Likewise.
+ * edit.c (_gpgme_op_edit_start): Likewise.
+ * encrypt.c (_gpgme_op_encrypt_start): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Likewise.
+ * export.c (_gpgme_op_export_start): Likewise.
+ * genkey.c (_gpgme_op_genkey_start): Likewise.
+ * import.c (_gpgme_op_import_start): Likewise.
+ * key.c (gpgme_get_key): Likewise.
+ * keylist.c (gpgme_op_keylist_start): Likewise.
+ (gpgme_op_keylist_ext_start): Likewise.
+ (gpgme_op_keylist_next): Likewise.
+ (gpgme_op_keylist_end): Likewise.
+ * data-compat.c (gpgme_error_to_errno): Don't convert EBUSY.
+
+2003-02-06 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (GpgmePassphraseCb): Change type to return GpgmeError,
+ and add argument for returning the result string.
+ (gpgme_cancel): Remove prototype.
+ * gpgme.c (gpgme_cancel): Remove function.
+ * context.h (struct gpgme_context_s): Remove member cancel.
+ * passphrase.c (_gpgme_passphrase_command_handler): Call the
+ passphrase callback in the new way.
+
+2003-01-30 Marcus Brinkmann <[email protected]>
+
+ * edit.c (_gpgme_edit_status_handler): Call the progress status
+ handler.
+
+2003-02-05 Marcus Brinkmann <[email protected]>
+
+ * wait-user.c (_gpgme_wait_user_remove_io_cb): Move check for no
+ I/O handlers left to ...
+ (_gpgme_user_io_cb_handler): ... here.
+
+2003-02-04 Marcus Brinkmann <[email protected]>
+
+ * trustlist.c (trustlist_colon_handler): Release ITEM if name
+ could not be allocated.
+ (gpgme_trust_item_release): Only release name if it is allocated.
+ Reported by Marc Mutz <[email protected]>.
+
+2003-02-04 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (read_status): If he status handler returns an error,
+ return it.
+ (status_handler): If read_status fails, just return the error.
+
+2003-02-01 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (start): Handle all errors, not only most of
+ them.
+ (xtoi_1, xtoi_2): Remove macro.
+ (status_handler): Replace use of xtoi_2 with _gpgme_hextobyte.
+
+2003-02-01 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (map_assuan_error): Replace
+ ASSUAN_Bad_Certificate_Path with ASSUAN_Bad_Certificate_Chain.
+ (gpgsm_new): Use assuan_pipe_connect instead assuan_pipe_connect2.
+
+ * util.h (DIMof): Remove macro.
+
+ * ops.h (_gpgme_op_event_cb, _gpgme_op_event_cb_user,
+ _gpgme_data_unread): Prototypes removed.
+
+2003-01-30 Marcus Brinkmann <[email protected]>
+
+ * types.h: File removed.
+ * Makefile.am (libgpgme_la_SOURCES): Remove types.h.
+ * io.h (struct spawn_fd_item_s): Do not include "types.h".
+ * key.h: Likewise.
+ * context.h: Likewise.
+ * cengine-gpgsm.h: Likewise.
+ * engine.h: Include "gpgme.h" instead "types.h". Add prototypes
+ for EngineStatusHandler, EngineColonLineHandler and
+ EngineCommandHandler.
+ (_gpgme_engine_set_status_handler): Change parameter type from
+ GpgmeStatusHandler to EngineStatusHandler.
+ (_gpgme_engine_set_command_handler): Change parameter type from
+ GpgmeCommandHandler to EngineCommandHandler.
+ (_gpgme_engine_set_colon_line_handler): Change parameter type from
+ GpgmeColonLineHandler to EngineColonLineHandler.
+ * engine-backend.h: Include "engine.h" instead "types.h".
+ (struct engine_ops): Change Gpgme*Handler parameters in members
+ set_command_handler, set_colon_line_handler and set_status_handler
+ to Engine*Handler.
+ * engine.c (_gpgme_engine_set_status_handler): Change parameter
+ type from GpgmeStatusHandler to EngineStatusHandler.
+ (_gpgme_engine_set_command_handler): Change parameter type from
+ GpgmeCommandHandler to EngineCommandHandler.
+ (_gpgme_engine_set_colon_line_handler): Change parameter type from
+ GpgmeColonLineHandler to EngineColonLineHandler.
+ * rungpg.c (struct gpg_object_s): Change type of member status.fnc
+ from GpgmeStatusHandler to EngineStatusHandler. Change type of
+ member colon.fnc from GpgmeColonLineHandler to
+ EngineColonLineHandler. Change type of member cmd.fnc from
+ GpgmeCommandHandler to EngineCommandHandler.
+ * engine-gpgsm.c (struct gpgsm_object_s): Likewise.
+ * rungpg.c (gpg_set_status_handler): Change parameter type from
+ GpgmeStatusHandler to EngineStatusHandler.
+ * engine-gpgsm.c (gpgsm_set_status_handler): Likewise.
+ (assuan_simple_command): Likewise.
+ * rungpg.c (gpg_set_colon_line_handler): Change parameter type
+ from GpgmeColonLineHandler to EngineColonLineHandler.
+ * engine-gpgsm.c (gpgsm_set_colon_line_handler): Likewise.
+ * rungpg.c (gpg_set_command_handler): Change parameter type from
+ GpgmeCommandHandler to EngineCommandHandler.
+
+ * engine-gpgsm.c (status_handler): Do not close status fd at end
+ of function.
+
+ * ops.h (_gpgme_op_data_lookup): Add prototype.
+ * op-support.c: Include <stdlib.h>.
+ (_gpgme_op_data_lookup): New function.
+ * decrypt.c (_gpgme_release_decrypt_result): Function removed.
+ (struct decrypt_result_s): Rename to ...
+ (struct decrypt_resul): ... this.
+ (DecryptResult): New type.
+ (_gpgme_decrypt_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ * sign.c (_gpgme_release_sign_result): Function removed.
+ (release_sign_result): New function.
+ (struct sign_result_s): Rename to ...
+ (struct sign_result): ... this.
+ (SignResult): New type.
+ (_gpgme_sign_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ * encrypt.c (struct encrypt_result_s): Rename to ...
+ (struct encrypt_result): ... this.
+ (_gpgme_release_encrypt_result): Function removed.
+ (release_encrypt_result): New function.
+ (_gpgme_encrypt_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ * verify.c (struct verify_result_s): Rename to ...
+ (struct verify_result): ... this. Remove member next.
+ (VerifyResult): New type.
+ (_gpgme_release_verify_result): Function removed.
+ (release_verify_result): New function.
+ (finish_sig): Change first argument to type VerifyResult. Diddle
+ the type of the op_data structure.
+ (add_notation): Change first argument to type VerifyResult.
+ (_gpgme_verify_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ * passphrase.c (struct passphrase_result_s): Rename to ...
+ (struct passphrase_result): ... this. Remove member next.
+ (PassphraseResult): New type.
+ (_gpgme_release_passphrase_result): Function removed.
+ (release_passphrase_result): New function.
+ (_gpgme_passphrase_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ (_gpgme_passphrase_command_handler): Likewise.
+ * keylist.c (struct keylist_result_s): Rename to ...
+ (struct keylist_result): ... this. Remove member next.
+ (KeylistResult): New type.
+ (_gpgme_release_keylist_result): Function removed.
+ (release_keylist_result): New function.
+ (keylist_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ * edit.c (struct edit_result_s): Rename to ...
+ (struct edit_result): ... this. Remove member next.
+ (EditResult): New type.
+ (_gpgme_release_edit_result): Function removed.
+ (release_edit_result): New function.
+ (edit_status_handler): Don't use
+ test_and_allocate_result, but use _gpgme_op_data_lookup to
+ retrieve result data object.
+ (command_handler): Likewise.
+ * types.h (DecryptResult, SignResult, EncryptResult,
+ PassphraseResult, ImportResult, DeleteResult, GenKeyResult,
+ KeylistResult, EditResult): Types removed.
+ * ops.h: Don't include "types.h", but "gpgme.h" and "context.h".
+ (test_and_allocate_result): Remove macro.
+ (_gpgme_release_decrypt_result): Remove prototype.
+ (_gpgme_decrypt_result): Remove prototype.
+ (_gpgme_release_sign_result): Remove prototype.
+ (_gpgme_release_encrypt_result): Remove prototype.
+ (_gpgme_release_passphrase_result): Remove prototype.
+ (_gpgme_release_import_result): Remove prototype.
+ (_gpgme_release_delete_result): Remove prototype.
+ (_gpgme_release_genkey_result): Remove prototype.
+ (_gpgme_release_keylist_result): Remove prototype.
+ (_gpgme_release_edit_result): Remove prototype.
+ (_gpgme_release_verify_result): Remove prototype.
+ * gpgme.c (_gpgme_release_result): Rewritten.
+ * context.h (enum ctx_op_data_type): New enum.
+ (struct ctx_op_data): New structure.
+ (struct gpgme_context_s): Replace the member result with a member
+ op_data.
+ (fail_on_pending_request): Remove macro.
+ * op-support.c (_gpgme_op_reset): Expand macro
+ fail_on_pending_request.
+ * util.h: Don't include "types.h" or "debug.h", but include "gpgme.h".
+
+2003-01-30 Marcus Brinkmann <[email protected]>
+
+ * types.h (EngineObject): Move typedef to ...
+ * engine.h: ... here.
+ * types.h (GpgObject): Move typedef to ...
+ * rungpg.c: ... here.
+ * types.h (GpgsmObject): Move typedef to ...
+ * engine-gpgsm.c: ... here.
+
+ * util.h (return_if_fail, return_null_if_fail,
+ return_val_if_fail): Remove macro.
+ * gpgme.c (gpgme_cancel): Don't use return_if_fail.
+ * key.c (gpgme_key_ref): Likewise.
+ * signers.c (gpgme_signers_enum): Likewise.
+ (gpgme_signers_clear): Likewise.
+
+ * engine-backend.h (struct engine_ops): Rename get_path to
+ get_file_name.
+ * gpgme.h (struct _gpgme_engine_info): Rename member path to
+ file_name.
+ * version.c: Do not include <stdio.h>, <stdlib.h>, context.h and
+ util.h. Other clean ups.
+ (parse_version_number): Protect more seriously against
+ overflow.
+ (gpgme_get_engine_info): Move to ...
+ * engine.c (gpgme_get_engine_info): ... here.
+ (_gpgme_engine_get_info): Function removed.
+ (_gpgme_engine_get_path): Make static and rename to ...
+ (engine_get_file_name): .. this.
+ (_gpgme_engine_get_version): Make static and rename to ...
+ (engine_get_version): ... this.
+ (_gpgme_engine_get_req_version): Make static and rename to ...
+ (engine_get_req_version): ... this.
+ * engine.h (_gpgme_engine_get_path, _gpgme_engine_get_version,
+ _gpgme_engine_req_version, _gpgme_engine_get_info.): Remove
+ prototypes.
+
+ * gpgme.h (enum GpgmeProtocol): Remove GPGME_PROTOCOL_AUTO.
+ * gpgme.c (gpgme_set_protocol): Don't handle GPGME_PROTOCOL_AUTO.
+ (gpgme_get_protocol_name): New function.
+
+ * engine-backend.h (struct engine_ops): New member
+ get_req_version, remove member check_version.
+ * engine.h (_gpgme_Engine_get_version): New prototype.
+ * rungpg.c (gpg_get_req_version): New function.
+ (gpg_check_version): Function removed.
+ (_gpgme_engine_ops_gpg): Add gpg_get_req_version, remove
+ gpg_check_version.
+ * engine-gpgsm.c (gpgsm_get_req_version): New function.
+ (gpgsm_check_version): Function removed.
+ (_gpgme_engine_ops_gpgsm): Add gpgsm_get_req_version, remove
+ gpgsm_check_version.
+ * engine.c: Include ops.h.
+ (_gpgme_engine_get_req_version): New function.
+ (gpgme_engine_check_version): Rewritten.
+ * version.c (gpgme_get_engine_info): Rewritten.
+ * gpgme.h (gpgme_engine_info): New structure.
+ (GpgmeEngineInfo): New type.
+
+2003-01-29 Marcus Brinkmann <[email protected]>
+
+ * types.h: Remove byte and ulong types.
+ * util.h (_gpgme_hextobyte): Change prototype to unsigned char
+ instead byte.
+ * conversion.c (_gpgme_hextobyte): Change argument to unsigned
+ char instead byte.
+ (_gpgme_decode_c_string): Likewise, and beautify. Also support a
+ few more escaped characters. Be more strict about buffer size.
+ (_gpgme_data_append_percentstring_for_xml): Change type of SRC,
+ BUF and DST to unsigned char instead byte.
+ * progress.c (_gpgme_progress_status_handler): Use unsigned char
+ instead byte.
+ * debug.c (trim_spaces): Likewise.
+
+ * util.h (mk_error): Remove macro.
+ * conversion.c, data.c, data-compat.c, decrypt.c, delete.c,
+ edit.c, encrypt.c, encrypt-sign.c, engine.c, engine-gpgsm.c,
+ export.c, genkey.c, gpgme.c, import.c, key.c, keylist.c,
+ passphrase.c, progress.c, recipient.c, rungpg.c, sign.c,
+ signers.c, trustlist.c, verify.c, wait.c, wait-global.c,
+ wait-private (literally everywhere): Expand the mk_error macro.
+
+ * context.h (wait_on_request_or_fail): Remove macro.
+
+ * 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.
+
+2003-01-19 Miguel Coca <[email protected]>
+
+ * w32-io.c (_gpgme_io_select): Add missing argument in calls to
+ DEBUG_BEGIN.
+ * w32-util.c: Include "sema.h".
+ (find_program_in_registry): Change DEBUG1 to DEBUG2, fixes compilation
+ error.
+
+2003-01-19 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_engine_ops_gpg): Remove gpg_start.
+ (gpg_start): Rename to ...
+ (start): ... this function. Change arguments to GpgObject.
+ (gpg_decrypt): Call start.
+ (gpg_edit): Likewise.
+ (gpg_encrypt): Likewise.
+ (gpg_encrypt_sign): Likewise.
+ (gpg_export): Likewise.
+ (gpg_import): Likewise.
+ (gpg_keylist): Likewise.
+ (gpg_keylist_ext): Likewise.
+ (gpg_trustlist): Likewise.
+ (gpg_verify): Likewise.
+
+ * engine-gpgsm.c (_gpgme_engine_ops_encrypt): Remove gpgsm_start.
+ (gpgsm_start): Rename to ...
+ (struct gpgsm_object_s): Remove member command.
+ (gpgsm_release): Don't free command.
+ (start): ... this function. Change arguments to GpgsmObject and
+ const char *.
+ (gpgsm_decrypt): Call start.
+ (gpgsm_delete): Likewise.
+ (gpgsm_encrypt): Likewise.
+ (gpgsm_export): Likewise.
+ (gpgsm_genkey): Likewise.
+ (gpgsm_import): Likewise.
+ (gpgsm_keylist): Likewise.
+ (gpgsm_keylist_ext): Likewise.
+ (gpgsm_verify): Likewise.
+
+ * decrypt.c (_gpgme_decrypt_start): Don't call
+ _gpgme_engine_start.
+ * delete.c (_gpgme_op_delete_start): Likewise.
+ * edit.c (_gpgme_op_edit_start): Likewise.
+ * encrypt.c (_gpgme_op_encrypt_start):
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start):
+ * export.c (_gpgme_op_export_start): Likewise.
+ * genkey.c (_gpgme_op_genkey_start): Likewise.
+ * import.c (_gpgme_op_import_start): Likewise.
+ * keylist.c (gpgme_op_keylist_ext_start): Likewise.
+ (gpgme_op_keylist_start): Likewise.
+ * sign.c (_gpgme_op_sign_start): Likewise.
+ * trustlist.c (gpgme_op_trustlist_start): Likewise.
+ * verify.c (_gpgme_op_verify_start): Likewise.
+
+ * engine-backend.h (struct engine_ops): Remove member start.
+
+ * engine.h (_gpgme_engine_start): Remove prototype.
+ * engine.c (_gpgme_engine_start): Remove function.
+
+2003-01-06 Werner Koch <[email protected]>
+
+ * keylist.c (set_mainkey_capability): Handle 'd' and 'D' used
+ since gpg 1.3 to denote disabled keys.
+
+2003-01-06 Marcus Brinkmann <[email protected]>
+
+ * data-mem.c: Include <string.h>.
+ * engine.c: Likewise.
+
+2003-01-06 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (libgpgme_la_DEPENDENCIES): Correct bug in last change.
+
+2002-12-24 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_op_verify, gpgme_op_decrypt_verify): Drop R_STAT
+ argument.
+ * decrypt-verify.c (gpgme_op_decrypt_verify): Drop R_STAT
+ argument.
+ * verify.c (gpgme_op_verify): Drop R_STAT argument.
+ (_gpgme_intersect_stati): Function removed.
+ * ops.h (_gpgme_intersect_stati): Remove prototype.
+
+2002-12-24 Marcus Brinkmann <[email protected]>
+
+ * libgpgme.vers: New file.
+ * Makefile.am (EXTRA_DIST): Add libgpgme.vers.
+ (libgpgme_version_script_cmd): New variable.
+ (libgpgme_la_LDFLAGS): Add libgpgme_version_script_cmd here.
+ (libgpgme_la_DEPENDENCIES): New variable.
+
+2002-12-23 Marcus Brinkmann <[email protected]>
+
+ * key.c (gpgme_key_get_string_attr): Don't accept GPGME_ATTR_IS_SECRET.
+ (otrust_to_string): New function.
+ (gpgme_key_get_as_xml): Use it.
+ (validity_to_string): New function.
+ (gpgme_key_get_string_attr): Beautify using above functions.
+ (gpgme_key_get_ulong_attr): Likewise.
+
+2002-12-23 Marcus Brinkmann <[email protected]>
+
+ * data-mem.c (mem_release): Fix gcc warning.
+ * data-user.c (user_release): Likewise.
+
+2002-12-06 Marcus Brinkmann <[email protected]>
+
+ * data.h (gpgme_data_release_cb): Change return type to void.
+ (gpgme_data_read_cb): Change return type to ssize_t.
+ * data.c (gpgme_data_read): Likewise.
+ * data-stream.c (stream_read): Likewise.
+ * data-fd.c (fd_read): Likewise.
+ * data-mem.c (mem_read): Likewise.
+ (mem_release): Change return type to void.
+ * data-user.c (user_read): Change return type to ssize_t.
+ (user_release): Change return type to void.
+ * data-compat.c (old_user_read): Change return type to ssize_t.
+ * gpgme.h (GpgmeDataReadCb): Likewise.
+ (gpgme_data_read): Likewise.
+ (GpgmeDataSeekCb): Change return type to off_t.
+
+2002-12-04 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add prototype for gpgme_get_key.
+ * key.c (gpgme_get_key): New function.
+ * verify.c (gpgme_get_sig_key): Rewrite using gpgme_get_key.
+
+ * gpgme.h: Add prototypes for new interfaces
+ gpgme_key_sig_get_string_attr and gpgme_key_get_ulong_attr.
+ (enum GpgmeAttr): New attribute GPGME_ATTR_SIG_CLASS.
+ * gpgme.c (gpgme_set_keylist_mode): Allow GPGME_KEYLIST_MODE_SIGS.
+ * key.h (struct certsig_s): New members ALGO, NAME_PART,
+ EMAIL_PART, COMMENT_PART, NAME, SIG_STAT and SIG_CLASS.
+
+ * conversion.c (_gpgme_decode_c_string): Add new parameter LEN.
+ Use that to determine if allocation is desired or not.
+ * util.h: Adjust prototype of _gpgme_decode_c_string.
+ * keylist.c (keylist_colon_handler): Adjust caller of
+ _gpgme_decode_c_string.
+
+ * key.h (struct gpgme_key_s): New member last_uid.
+ * key.c (_gpgme_key_append_name): Rewritten using
+ _gpgme_decode_c_string and the last_uid pointer.
+ (my_isdigit): Macro removed.
+ (ALLOC_CHUNK): Likewise.
+ * keylist.c (set_userid_flags): Use last_uid member of KEY.
+
+ * context.h (struct user_id_s): New member last_certsig.
+ * key.h: Add prototype for _gpgme_key_add_certsig.
+ * key.c (_gpgme_key_add_certsig): New function.
+ (set_user_id_part): Move function before _gpgme_key_add_certsig.
+ (parse_user_id): Change first argument to SRC, add new arguments
+ NAME, EMAIL and COMMENT. Change code to use these arguments
+ instead going through UID. Move function before
+ _gpgme_add_certsig.
+ (parse_x509_user_id): Likewise.
+ (_gpgme_key_append_name): Adjust arguments to parse_x509_user_id
+ and parse_user_id invocation.
+ (one_certsig_as_xml): New function.
+ (one_uid_as_xml): Print signatures.
+ * context.h (struct gpgme_context_s): New member TMP_UID.
+ * keylist.c (keylist_colon_handler): Rewritten, implement "sig"
+ record entries.
+
+ * key.c (get_certsig): New function.
+ (gpgme_key_sig_get_string_attr): Likewise.
+ (gpgme_key_sig_get_ulong_attr): Likewise.
+
+ * keylist.c: Include <ctype.h>.
+ (my_isdigit): Macro removed.
+ (set_mainkey_trust_info): Use isdigit, not my_isdigit.
+ (set_userid_flags): Likewise.
+ (set_subkey_trust_info): Likewise.
+ (set_ownertrust): Likewise.
+ (finish_key): Move function up a bit and remove prototype.
+
+ * rungpg.c (gpg_keylist_ext): Correct precedence of signature
+ listing mode.
+ (gpg_keylist_ext): Implement signature listing mode.
+
+2002-11-25 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_spawn): Do not set parent fds to -1.
+ * posix-io.c (_gpgme_io_spawn): Call _gpgme_io_close instead close
+ for parent fds.
+ * w32-io.c (_gpgme_io_spawn): Call _gpgme_io_close instead
+ CloseHandle for parent fds.
+
+2002-11-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h [_MSC_VER]: Define ssize_t as long.
+
+2002-11-22 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): Save the result of a first
+ setlocale before doing another setlocale.
+
+2002-11-21 Marcus Brinkmann <[email protected]>
+
+ * decrypt.c: Some beautyfication.
+
+ * verify.c (_gpgme_verify_status_handler): Treat
+ GPGME_STATUS_UNEXPECTED like GPGME_STATUS_NODATA.
+ Reported by Miguel Coca <[email protected]>.
+
+2002-11-19 Marcus Brinkmann <[email protected]>
+
+ * genkey.c: Only include <config.h> if [HAVE_CONFIG_H].
+ (struct genkey_result_s): Add new member FPR.
+ (_gpgme_release_genkey_result): Free RESULT->fpr if set.
+ (genkey_status_handler): Extract the fingerprint from the status
+ line.
+ (gpgme_op_genkey): Add new argument FPR and return the fingerprint
+ in it.
+ * gpgme.h: Adjust prototype of gpgme_op_genkey.
+
+2002-11-19 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (gpg_keylist): Add --with-fingerprint to gpg invocation
+ twice, to get fingerprints on subkeys. Suggested by Timo Schulz
+ (gpg_keylist_ext): Likewise.
+
+2002-11-05 Marcus Brinkmann <[email protected]>
+
+ * import.c (append_xml_impinfo): Use
+ _gpgme_data_append_string_for_xml rather than
+ _gpgme_data_append_string for the field content.
+ Submitted by Miguel Coca <[email protected]>.
+
+2002-10-10 Marcus Brinkmann <[email protected]>
+
+ * rungpg.h, engine-gpgsm.h: File removed.
+ * engine-backend.h: New file.
+ * Makefile.am (gpgsm_components): New variable, set depending on
+ automake conditional HAVE_GPGSM.
+ (libgpgme_la_SOURCES): Add engine-backend.h, remove rungpg.h and
+ engine-gpgsm.h. Replace engine-gpgsm.c with ${gpgsm_components}.
+ (status-table.h): Depend on gpgme.h, not rungpg.h.
+ * conversion.c: Include <stdlib.h>.
+ * engine-gpgsm.c: Do not set ENABLE_GPGSM here. Include
+ "engine-backend.h" instead "engine-gpgsm.h". Reorder some
+ functions and remove all function prototypes.
+ (_gpgme_gpgsm_get_version): Make static and rename to ...
+ (gpgsm_get_version): ... this.
+ (_gpgme_gpgsm_check_version): Make static and rename to ...
+ (gpgsm_check_version): ... this.
+ (_gpgme_gpgsm_new): Make static. Change argument type from
+ GpgsmObject * to void **. Call gpgsm_release instead
+ _gpgme_gpgsm_release.
+ (_gpgme_gpgsm_op_decrypt): Make static and rename to ...
+ (gpgsm_check_decrypt): ... this.
+ (_gpgme_gpgsm_op_delete): Make static and rename to ...
+ (gpgsm_check_delete): ... this.
+ (_gpgme_gpgsm_set_recipients): Make static and rename to ...
+ (gpgsm_check_set_recipients): ... this.
+ (_gpgme_gpgsm_op_encrypt): Make static and rename to ...
+ (gpgsm_encrypt): ... this.
+ (_gpgme_gpgsm_op_export): Make static and rename to ...
+ (gpgsm_export): ... this.
+ (_gpgme_gpgsm_op_genkey): Make static and rename to ...
+ (gpgsm_genkey): ... this.
+ (_gpgme_gpgsm_op_import): Make static and rename to ...
+ (gpgsm_import): ... this.
+ (_gpgme_gpgsm_op_keylist): Make static and rename to ...
+ (gpgsm_keylist): ... this.
+ (_gpgme_gpgsm_op_keylist_ext): Make static and rename to ...
+ (gpgsm_keylist_ext): ... this.
+ (_gpgme_gpgsm_op_sign): Make static and rename to ...
+ (gpgsm_sign): ... this.
+ (_gpgme_gpgsm_op_trustlist): Make static and rename to ...
+ (gpgsm_trustlist): ... this.
+ (_gpgme_gpgsm_op_verify): Make static and rename to ...
+ (gpgsm_verify): ... this.
+ (gpgsm_status_handler): Rename to ...
+ (status_handler): ... this.
+ (_gpgme_gpgsm_set_status_handler): Make static and rename to ...
+ (gpgsm_set_status_handler): ... this.
+ (_gpgme_gpgsm_set_colon_line_handler): Make static and rename to ...
+ (gpgsm_set_colon_line_handler): ... this.
+ (_gpgme_gpgsm_add_io_cb): Rename to ...
+ (add_io_cb): ... this.
+ (_gpgme_gpgsm_start): Make static and rename to ...
+ (gpgsm_start): ... this.
+ (_gpgme_gpgsm_set_io_cb): Make static and rename to ...
+ (gpgsm_set_io_cb): ... this.
+ (_gpgme_gpgsm_io_event): Make static and rename to ...
+ (gpgsm_io_event): ... this.
+ (struct _gpgme_engine_ops_gpgsm): New variable.
+ [!ENABLE_GPGSM]: Removed.
+ * engine.c: Do not include <time.h>, <sys/types.h>, <string.h>,
+ <assert.h>, "io.h", "rungpg.h" and "engine-gpgsm.h". Include
+ <stdlib.h> and "engine-backend.h".
+ (struct engine_object_s): Rewritten.
+ (engine_ops): New variable.
+ * engine.c (_gpgme_engine_get_path, _gpgme_engine_get_version,
+ _gpgme_engine_check_version, _gpgme_engine_new,
+ _gpgme_engine_release, _gpgme_engine_set_verbosity,
+ _gpgme_engine_set_status_handler,
+ _gpgme_engine_set_command_handler,
+ _gpgme_engine_set_colon_line_handler, _gpgme_engine_op_decrypt,
+ _gpgme_engine_op_delete, _gpgme_engine_op_edit,
+ _gpgme_engine_op_encrypt, _gpgme_engine_op_encrypt_sign,
+ _gpgme_engine_op_export, _gpgme_engine_op_genkey,
+ _gpgme_engine_op_import, _gpgme_engine_op_keylist,
+ _gpgme_engine_op_keylist_ext, _gpgme_engine_op_sign,
+ _gpgme_engine_op_trustlist, _gpgme_engine_op_verify,
+ _gpgme_engine_start, _gpgme_engine_set_io_cbs,
+ _gpgme_engine_io_event): Reimplement.
+ * engine.h: Fix a few comments and a variable name in a prototype.
+ * ops.h: Do not include "rungpg.h".
+ * passphrase.c: Include config.h only if [HAVE_CONFIG_H]. Do not
+ include "rungpg.h".
+ * recipient.c: Likewise.
+ * signers.c: Likewise.
+ * version.c: Likewise.
+ * rungpg.c: Likewise. Include "engine-backend.h". Reorder
+ functions and remove prototypes.
+ (_gpgme_gpg_get_version): Make static and rename to ...
+ (gpg_get_version): ... this.
+ (_gpgme_gpg_check_version): Make static and rename to ...
+ (gpg_check_version): ... this.
+ (_gpgme_gpg_new): Make static. Change argument type from
+ GpgObject * to void **. Call gpg_release instead
+ _gpgme_gpg_release.
+ (_gpgme_gpg_op_decrypt): Make static and rename to ...
+ (gpg_check_decrypt): ... this.
+ (_gpgme_gpg_op_delete): Make static and rename to ...
+ (gpg_check_delete): ... this.
+ (_gpgme_gpg_set_recipients): Make static and rename to ...
+ (gpg_check_set_recipients): ... this.
+ (_gpgme_gpg_op_encrypt): Make static and rename to ...
+ (gpg_encrypt): ... this.
+ (_gpgme_gpg_op_export): Make static and rename to ...
+ (gpg_export): ... this.
+ (_gpgme_gpg_op_genkey): Make static and rename to ...
+ (gpg_genkey): ... this.
+ (_gpgme_gpg_op_import): Make static and rename to ...
+ (gpg_import): ... this.
+ (_gpgme_gpg_op_keylist): Make static and rename to ...
+ (gpg_keylist): ... this.
+ (_gpgme_gpg_op_keylist_ext): Make static and rename to ...
+ (gpg_keylist_ext): ... this.
+ (_gpgme_gpg_op_sign): Make static and rename to ...
+ (gpg_sign): ... this.
+ (_gpgme_gpg_op_trustlist): Make static and rename to ...
+ (gpg_trustlist): ... this.
+ (_gpgme_gpg_op_verify): Make static and rename to ...
+ (gpg_verify): ... this.
+ (gpg_status_handler): Rename to ...
+ (status_handler): ... this.
+ (_gpgme_gpg_set_status_handler): Make static and rename to ...
+ (gpg_set_status_handler): ... this.
+ (_gpgme_gpg_set_colon_line_handler): Make static and rename to ...
+ (gpg_set_colon_line_handler): ... this.
+ (gpgme_gpg_add_io_cb): Rename to ...
+ (add_io_cb): ... this.
+ (_gpgme_gpg_start): Make static and rename to ...
+ (gpg_start): ... this.
+ (_gpgme_gpg_set_io_cb): Make static and rename to ...
+ (gpg_set_io_cb): ... this.
+ (_gpgme_gpg_io_event): Make static and rename to ...
+ (gpg_io_event): ... this.
+ (struct _gpgme_engine_ops_gpg): New variable.
+
+2002-10-10 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_verify) [!ENABLE_GPGSM]: Add
+ missing argument.
+
+2002-10-09 Marcus Brinkmann <[email protected]>
+
+ * data.h, data-user.c, data-stream.c, data-mem.c, data-fd.c,
+ data-compat.c: New file. Really check them in this time, completes
+ 2002-10-08 change.
+
+ * rungpg.h (GpgStatusHandler): Rename type to GpgmeStatusHandler
+ and move to ...
+ * types.h (GpgmeStatusHandler): ... here.
+ * rungpg.h (GpgColonLineHandler): Rename type to GpgmeColonLineHandler.
+ and move to ...
+ * types.h (GpgmeColonLineHandler): ... here.
+ * rungpg.h (GpgCommandHandler): Rename type to GpgmeCommandHandler.
+ and move to ...
+ * types.h (GpgmeCommandHandler): ... here.
+ * engine.h: Don't include "rungpg.h".
+ (_gpgme_engine_set_status_handler): Change type of
+ argument from GpgStatusHandler to GpgmeStatusHandler.
+ (_gpgme_engine_set_colon_line_handler): Change type of
+ argument from GpgColonLineHandler to GpgmeColonLineHandler.
+ (_gpgme_engine_set_command_handler): Change type of
+ argument from GpgCommandHandler to GpgmeCommandHandler.
+ * engine-gpgsm.h: Don't include "rungpg.h".
+ (_gpgme_gpgsm_set_status_handler): Change type of
+ argument from GpgStatusHandler to GpgmeStatusHandler.
+ (_gpgme_gpgsm_set_colon_line_handler): Change type of
+ argument from GpgColonLineHandler to GpgmeColonLineHandler.
+ * engine-gpgsm.c: Do not include "rungpg.h".
+ (struct gpgsm_object_s): Change type of
+ status.fnc to GpgmeStatusHandler. Change type of colon.fnc to
+ GpgmeColonLineHandler.
+ (gpgsm_assuan_simple_command): Change type of argument from
+ GpgStatusHandler to GpgmeStatusHandler.
+ (_gpgme_gpgsm_set_status_handler): Likewise.
+ (_gpgme_gpgsm_set_colon_line_handler): Change type of argument from
+ GpgColonLineHandler to GpgmeColonLineHandler.
+ * rungpg.h (_gpgme_gpg_set_status_handler): Change type of
+ argument from GpgStatusHandler to GpgmeStatusHandler.
+ (_gpgme_gpg_set_colon_line_handler): Change type of
+ argument from GpgColonLineHandler to GpgmeColonLineHandler.
+ (_gpgme_gpg_set_command_handler): Change type of
+ argument from GpgCommandHandler to GpgmeCommandHandler.
+ * rungpg.c (struct gpg_object_s): Change type of status.fnc to
+ GpgmeStatusHandler. Change type of colon.fnc to
+ GpgmeColonLineHandler. Change type of cmd.fnc to
+ GpgmeCommandLineHandler.
+ (_gpgme_gpg_set_status_handler): Change type of argument FNC to
+ GpgmeStatusHandler.
+ (_gpgme_gpg_set_colon_line_handler): Change type of argument FNC
+ to GpgmeColonLineHandler.
+ (_gpgme_gpg_set_command_handler): Change type of argument FNC to
+ GpgmeCommandHandler.
+ * engine.c (_gpgme_engine_set_status_handler): Change type of
+ argument FNC to GpgmeStatusHandler.
+ (_gpgme_engine_set_colon_line_handler): Change type of argument FNC
+ to GpgmeColonLineHandler.
+ (_gpgme_engine_set_command_handler): Change type of argument FNC to
+ GpgmeCommandHandler.
+
+ * rungpg.h (_gpgme_gpg_enable_pipemode): Remove prototype.
+ * rungpg.c (struct gpg_object_s): Remove PM.
+ (pipemode_cb): Prototype removed.
+ (add_pm_data): Function removed.
+ (_gpgme_gpg_enable_pipemode): Likewise.
+ (pipemode_copy): Likewise.
+ (pipemode_cb): Likewise.
+ (add_arg): Don't check for pipemode.
+ (add_data): Likewise.
+ (_gpgme_gpg_set_status_handler): Likewise.
+ (_gpgme_gpg_set_colon_line_handler): Likewise.
+ (_gpgme_gpg_set_command_handler): Likewise.
+ (_gpgme_gpg_spawn): Likewise.
+ (_gpgme_gpg_spawn): Don't set PM.active.
+ (_gpgme_gpg_op_verify): Remove pipemode case.
+ * verify.c (_gpgme_op_verify_start): Remove pipemode case.
+
+ * rungpg.h (_gpgme_gpg_add_arg, _gpgme_gpg_add_data,
+ _gpgme_gpg_add_pm_data, _gpgme_gpg_housecleaning,
+ _gpgme_gpg_set_simple_line_handler): Prototype removed.
+ (_gpgme_gpg_set_verbosity): New prototype.
+ * rungpg.c (_gpgme_gpg_add_data): Make static and rename to ...
+ (add_data): ... this.
+ (_gpgme_gpg_add_pm_data): Call add_data, not _gpgme_gpg_add_data.
+ (_gpgme_gpg_set_command_handler): Likewise.
+ (_gpgme_gpg_op_decrypt, _gpgme_gpg_op_edit, _gpgme_gpg_op_encrypt,
+ _gpgme_gpg_op_encrypt_sign, _gpgme_gpg_op_export,
+ _gpgme_gpg_op_genkey, _gpgme_gpg_op_import, _gpgme_gpg_op_sign,
+ _gpgme_gpg_op_verify): Likewise.
+ (_gpgme_gpg_add_pm_data): Rename to ...
+ (add_pm_data): ... this.
+ (_gpgme_gpg_op_verify): Call add_pm_data, not
+ _gpgme_gpg_add_pm_data.
+ (_gpgme_gpg_add_arg): Make static and rename to ...
+ (add_arg): ... this.
+ (_gpgme_gpg_set_command_handler, _gpgme_gpg_new,
+ _gpgme_gpg_op_decrypt, _gpgme_gpg_op_delete,
+ _gpgme_append_gpg_args_from_signers, _gpgme_gpg_op_edit,
+ _gpgme_append_gpg_args_from_recipients, _gpgme_gpg_op_encrypt,
+ _gpgme_gpg_op_encrypt_sign, _gpgme_gpg_op_export,
+ _gpgme_gpg_op_genkey, _gpgme_gpg_op_import, _gpgme_gpg_op_keylist,
+ _gpgme_gpg_op_keylist_ext, _gpgme_gpg_op_trustlist,
+ _gpgme_gpg_op_sign, _gpgme_gpg_op_verify): Use add_arg, not
+ _gpgme_gpg_add_arg.
+ (_gpgme_gpg_set_verbosity): New function.
+ (struct gpg_object_s): Remove member simple from colon.
+ (_gpgme_gpg_set_colon_line_handler): Don't initialize simple.
+ (_gpgme_gpg_set_simple_line_handler): Removed function.
+ (read_colon_line): Don't check the GPG->colon.simple.
+ * engine.c (_gpgme_engine_set_verbosity): Call
+ _gpgme_gpg_set_verbosity instead _gpgme_gpg_add_arg.
+
+2002-10-08 Marcus Brinkmann <[email protected]>
+
+ * util.h (_gpgme_malloc, _gpgme_realloc, _gpgme_calloc,
+ _gpgme_strdup, _gpgme_free): Remove prototypes.
+ (xtrymalloc, xtrycalloc, xtryrealloc, xtrystrdup, xfree): Remove
+ macros.
+ * util.c: File removed.
+ * Makefile.am (libgpgme_la_SOURCES): Remove util.h.
+ * conversion.c (_gpgme_decode_c_string): Use malloc instead of
+ xtrymalloc, realloc instead of xtryrealloc, calloc instead of
+ xtrycalloc, free instead of xfree.
+ (_gpgme_data_append_percentstring_for_xml): Likewise.
+ * data.c (_gpgme_data_new, _gpgme_data_release): Likewise.
+ * data-compat.c (gpgme_data_new_from_filepart): Likewise.
+ * data-mem.c (mem_write, mem_release, gpgme_data_new_from_mem,
+ _gpgme_data_get_as_string): Likewise.
+ * debug.c (debug_init): Likewise.
+ * decrypt.c (_gpgme_release_decrypt_result): Likewise.
+ * delete.c (_gpgme_release_delete_result): Likewise.
+ * edit.c (_gpgme_release_edit_result, _gpgme_op_edit_start):
+ Likewise.
+ * encrypt.c (_gpgme_release_encrypt_result): Likewise.
+ * engine.c (_gpgme_engine_get_info, _gpgme_engine_new,
+ _gpgme_engine_release): Likewise.
+ * engine-gpgsm.c (_gpgme_gpgsm_new, _gpgme_gpgsm_release,
+ _gpgme_gpgsm_op_decrypt, _gpgme_gpgsm_op_delete,
+ gpgsm_set_recipients, _gpgme_gpgsm_op_encrypt,
+ _gpgme_gpgsm_op_export, _gpgme_gpgsm_op_genkey,
+ _gpgme_gpgsm_op_import, _gpgme_gpgsm_op_keylist,
+ _gpgme_gpgsm_op_keylist_ext, _gpgme_gpgsm_op_sign,
+ _gpgme_gpgsm_op_verify, gpgsm_status_handler): Likewise.
+ * genkey.c (_gpgme_release_genkey_result): Likewise.
+ * gpgme.c (gpgme_new, gpgme_release): Likewise.
+ * import.c (_gpgme_release_import_result): Likewise.
+ * key.c (_gpgme_key_cache_init, _gpgme_key_cache_add, key_new,
+ add_subkey, gpgme_key_release, _gpgme_key_append_name): Likewise.
+ * keylist.c (_gpgme_release_keylist_result, keylist_colon_handler,
+ _gpgme_op_keylist_event_cb, gpgme_op_keylist_next): Likewise.
+ * ops.h (test_and_allocate_result): Likewise.
+ * passphrase.c (_gpgme_release_passphrase_result,
+ _gpgme_passphrase_status_handler,
+ _gpgme_passphrase_command_handler): Likewise.
+ * progress.c (_gpgme_progress_status_handler): Likewise.
+ * recipient.c (gpgme_recipients_new, gpgme_recipients_release,
+ gpgme_recipients_add_name_with_validity): Likewise.
+ * rungpg.c (_gpgme_gpg_new, _gpgme_gpg_release,
+ _gpgme_gpg_add_arg, _gpgme_gpg_add_data,
+ _gpgme_gpg_set_colon_line_handler, free_argv, free_fd_data_map,
+ build_argv, _gpgme_gpg_spawn, read_status, read_colon_line):
+ Likewise.
+ * sign.c (_gpgme_release_sign_result): Likewise.
+ * signers.c (_gpgme_signers_add): Likewise.
+ * trustlist.c (trust_item_new, trustlist_colon_handler,
+ _gpgme_op_trustlist_event_cb, gpgme_op_trustlist_next,
+ gpgme_trustitem_release): Likewise.
+ * verify.c (_gpgme_release_verify_result, finish_sig): Likewise.
+ * version.c (gpgme_get_engine_info, _gpgme_get_program_version):
+ Likewise.
+ * w32-io.c (create_reader, create_writer, destroy_reader,
+ destroy_writer, build_commandline, _gpgme_io_spawn): Likewise.
+ * w32-sema.c (critsect_init, _gpgme_sema_cs_destroy): Likewise.
+ * w32-util.c (read_w32_registry_string): Likewise.
+ * wait.c (_gpgme_fd_table_deinit, _gpgme_fd_table_put,
+ _gpgme_wait_event_cb, _gpgme_add_io_cb, _gpgme_remove_io_cb)
+ * data-compat.c: Include <stdlib.h>.
+
+2002-10-08 Marcus Brinkmann <[email protected]>
+
+ New data object component:
+
+ * gpgme.h (GpgmeDataReadCb, GpgmeDataWriteCb, GpgmeDataSeekCb,
+ GpgmeDataReleaseCb): New types.
+ (struct GpgmeDataCbs): New structure.
+ (gpgme_data_read): Changed prototype to match that of read() closely.
+ (gpgme_data_write): Similar for write().
+ (gpgme_data_seek, gpgme_data_new_from_cbs, gpgme_data_new_from_fd,
+ gpgme_data_new_from_stream): New prototypes.
+ (gpgme_data_get_type, gpgme_check_engine): Prototype removed.
+
+ * Makefile.am (libgpgme_la_SOURCES): Add data.h, data-fd.c,
+ data-stream.c, data-mem.c, data-user.c and data-compat.c.
+ * data.c: Reimplemented from scratch.
+ * (data-compat.c, data-fd.c, data.h, data-mem.c, data-stream.c,
+ data-user.c): New file.
+ * context.h (struct gpgme_data_s): Removed.
+ * conversion.c: Include <errno.h> and <sys/types.h>.
+ (_gpgme_data_append): New function.
+ * data.c (_gpgme_data_append_string): Move to ...
+ * conversion.c (_gpgme_data_append_string): ... here.
+ * data.c (_gpgme_data_append_for_xml): Move to ...
+ * conversion.c (_gpgme_data_append_for_xml): ... here.
+ * data.c (_gpgme_data_append_string_for_xml): Move to ...
+ * conversion.c (_gpgme_data_append_string_for_xml): ... here.
+ * data.c (_gpgme_data_append_percentstring_for_xml): Move to ...
+ * conversion.c (_gpgme_data_append_percentstring_for_xml): ... here.
+
+ * ops.h (_gpgme_data_get_mode, _gpgme_data_set_mode): Prototype
+ removed.
+ * types.h (GpgmeDataMode): Type removed.
+
+ * decrypt.c (_gpgme_decrypt_start): Don't check data type or mode.
+ * edit.c (_gpgme_op_edit_start): Likewise.
+ * encrypt.c (_gpgme_op_encrypt_start): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Likewise.
+ * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Likewise.
+ * export.c (_gpgme_op_export_start): Likewise.
+ * genkey.c (_gpgme_op_genkey_start): Likewise.
+ * import.c (_gpgme_op_import_start): Likewise.
+ * sign.c (_gpgme_op_sign_start): Likewise.
+ * verify.c (_gpgme_op_verify_start): Likewise.
+
+ * encrypt.c (gpgme_op_encrypt): Remove hack that returns invalid
+ no recipient if no data was returned.
+ * encrypt-sign.c (gpgme_op_encrypt_sign): Remove hack that returns
+ no recipient if no data was returned.
+ * encrypt-sign.c (gpgme_op_encrypt_sign): Remove hack that returns
+ no recipient if no data was returned.
+
+ * engine.c (_gpgme_engine_op_verify): Add new argument to
+ differentiate detached from normal signatures.
+ * engine.h (_gpgme_engine_op_verify): Likewise for prototype.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_verify): Likewise. Don't check
+ mode of data argument.
+ * engine-gpgsm.h (_gpgme_gpgsm_op_verify): Likewise for prototype.
+ * gpgme.h (gpgme_op_verify_start): Likewise for prototype.
+ (gpgme_op_verify): Likewise for prototype.
+ * rungpg.c (_gpgme_gpg_op_verify): Likewise.
+ * rungpg.h (_gpgme_gpg_op_verify): Likewise for prototype.
+ * verify.c (_gpgme_op_verify_start): Likewise.
+ (gpgme_op_verify_start): Likewise.
+ (gpgme_op_verify): Likewise.
+
+ * rungpg.c (struct arg_and_data_s): New member INBOUND to hold
+ direction of data object.
+ (_gpgme_gpg_add_data): Add new argument INBOUND. Use it to
+ determine direction of data object.
+ (_gpgme_gpg_add_pm_data, _gpgme_gpg_set_command_handler,
+ _gpgme_gpg_op_decrypt, _gpgme_gpg_op_edit, _gpgme_gpg_op_encrypt,
+ _gpgme_gpg_op_encrypt_sign, _gpgme_gpg_op_export,
+ _gpgme_gpg_op_genkey, _gpgme_gpg_op_import, _gpgme_gpg_op_sign,
+ _gpgme_gpg_op_verify): Add new argument to _gpgme_gpg_add_data
+ invocation.
+ (build_argv): Use new member INBOUND to determine direction of
+ file descriptor. Don't check the data type.
+ * rungpg.h (_gpgme_gpg_add_data): Add new argument to prototype.
+
+ * gpgme.c (gpgme_get_op_info): Don't call
+ _gpgme_data_get_as_string if CTX->op_info is NULL.
+
+ * version.c (gpgme_check_engine): Function removed.
+
+2002-09-30 Werner Koch <[email protected]>
+
+ * keylist.c (keylist_colon_handler): Take care when printing a
+ NULL with the DEBUG.
+
+ * engine-gpgsm.c (struct gpgsm_object_s): New member ANY.
+ (gpgsm_status_handler): Run the colon function to indicate EOF.
+ (_gpgme_gpgsm_set_colon_line_handler): Better reset ANY here.
+
+2002-09-28 Marcus Brinkmann <[email protected]>
+
+ * conversion.c (_gpgme_hextobyte): Prevent superfluous
+ multiplication with base. Reported by St�phane Corth�sy.
+
+ * keylist.c (gpgme_op_keylist_ext_start): Use private asynchronous
+ operation type in invocation of _gpgme_op_reset.
+
+2002-09-20 Werner Koch <[email protected]>
+
+ * ath.c: Include sys/time.h if sys/select.h is not available.
+
+2002-09-13 Marcus Brinkmann <[email protected]>
+
+ * keylist.c (keylist_status_handler): Do not call finish_key() here.
+ (gpgme_op_keylist_ext_start): Set CTX->tmp_key to NULL.
+
+2002-09-03 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (assuan_libobjs): Remove @LTLIBOBJS@ as we link them
+ into gpgme unconditionally.
+ (libgpgme_la_LIBADD): Change @LIBOBJS@ into @LTLIBOBJS@.
+
+2002-09-02 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (assuan_libobjs): Use @LTLIBOBJS@ instead @LIBOBJS@.
+
+2002-09-02 Marcus Brinkmann <[email protected]>
+
+ * debug.c (_gpgme_debug_add): Test *LINE, not LINE.
+ (_gpgme_debug_end): Likewise.
+ Reported by Dr. Stefan Dalibor <[email protected]>.
+
+2002-09-02 Marcus Brinkmann <[email protected]>
+
+ * posix-io.c (_gpgme_io_select): Don't use a non-constant struct
+ initializer.
+ * version.c (_gpgme_get_program_version): Likewise.
+ Reported by Dr. Stefan Dalibor <[email protected]>.
+
+2002-09-02 Marcus Brinkmann <[email protected]>
+
+ * conversion.c (_gpgme_decode_c_string): Set DESTP before
+ modifying DEST.
+
+ * conversion.c (_gpgme_decode_c_string): Fix off by one error in
+ last change.
+ * rungpg.c (_gpgme_append_gpg_args_from_signers): Move before
+ _gpgme_op_edit so its prototype is known early on.
+
+ * conversion.c: New file.
+ * util.h: Add prototypes for _gpgme_decode_c_string and
+ _gpgme_hextobyte.
+ * keylist.c (keylist_colon_handler): Call _gpgme_decode_c_string
+ on issuer name.
+ * Makefile.am (libgpgme_la_SOURCES): Add conversion.c
+ * key.c (_gpgme_key_append_name): Replace calls to hextobyte by
+ calls to _gpgme_hextobyte.
+ (hash_key): Likewise.
+
+2002-09-01 Marcus Brinkmann <[email protected]>
+
+ * op-support.c (_gpgme_op_reset): Set CTX->pending after calling
+ _gpgme_engine_release, as this will reset pending to zero in the
+ event done callback on cancelled operations.
+
+2002-08-30 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_op_edit): Add args from signers.
+ Suggested by Miguel Coca <[email protected]>.
+
+ * rungpg.c (_gpgme_gpg_op_edit): Add bogus ctx argument.
+ * rungpg.h: Also to prototype.
+ * engine.c (_gpgme_engine_op_edit): Likewise.
+ * engine.h: Likewise.
+ * edit.c (_gpgme_op_edit_start): Likewise.
+
+2002-08-29 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Implement signer
+ selection.
+ * vasprintf.c (va_copy): Define macro if not yet defined.
+
+2002-08-29 Marcus Brinkmann <[email protected]>
+
+ * passphrase.c (_gpgme_passphrase_status_handler): Reset
+ CTX->result.passphrase->no_passphrase if passphrase is given (good
+ or bad). Submitted by Jean DIRAISON <[email protected]>.
+
+2002-08-28 Marcus Brinkmann <[email protected]>
+
+ * posix-io.c (_gpgme_io_spawn): Use a double-fork approach.
+ Return 0 on success, -1 on error.
+ * version.c (_gpgme_get_program_version): Don't wait for the child.
+ * engine.c (_gpgme_engine_housecleaning): Function removed.
+ (do_reaping): Likewise.
+ (_gpgme_engine_add_child_to_reap_list): Likewise.
+ (struct reap_s): Removed.
+ (reap_list): Likewise.
+ (reap_list_lock): Likewise.
+ * engine.h (_gpgme_engine_io_event): Remove prototypes for
+ _gpgme_engine_housecleaning and
+ _gpgme_engine_add_child_to_reap_list.
+ * rungpg.c (_gpgme_gpg_release): Don't add child to reap list.
+ (struct gpg_object_s): Remove PID member.
+ (_gpgme_gpg_new): Don't initialize GPG->pid.
+ (_gpgme_gpg_spawn): Don't set GPG->pid.
+ * wait.c (run_idle): Removed.
+ (gpgme_wait): Run idle_function directly.
+
+2002-08-21 Marcus Brinkmann <[email protected]>
+
+ * encrypt-sign.c (encrypt_sign_status_handler): Remove dead
+ variables encrypt_info and encrypt_info_len.
+ * trustlist.c (gpgme_op_trustlist_start): Set colon line handler.
+ * posix-sema.c (sema_fatal): Remove function.
+ All these reported by St�phane Corth�sy.
+
+2002-08-23 Werner Koch <[email protected]>
+
+ * gpgme-config.in: Made --prefix work for --libs.
+
+2002-08-21 Marcus Brinkmann <[email protected]>
+
+ * ath.h: Update list of symbols that get a prefix: Rename the
+ ath_mutex_*_available symbols to ath_*_available.
+
+2002-08-21 Marcus Brinkmann <[email protected]>
+
+ * stpcpy.c: New file from gnulib.
+ * Makefile.am (assuan_libobjs): Remove jnlib.
+
+2002-08-20 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add prototype for gpgme_op_import_ext.
+ * import.c (struct import_result_s): New member `nr_considered'.
+ Rename `any_imported' to `nr_imported'.
+ (import_status_handler): Increment nr_imported. Set nr_considered
+ if appropriate.
+ (gpgme_op_import_ext): New function.
+ (gpgme_op_import): Implement in terms of gpgme_op_import_ext.
+
+2002-08-20 Werner Koch <[email protected]>
+
+ * gpgme.m4: Replaced with a new and faster version. This does not
+ anymore try to build test programs. If we really need test
+ programs, we should add an option to gpgme-config to do so.
+
+ * vasprintf.c (int_vasprintf): Hack to handle NULL passed for %s.
+
+2002-08-20 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (_gpgme_set_op_info): Append data on subsequent calls.
+ * encrypt-sign.c (encrypt_sign_status_handler): Remove op_info
+ handling.
+
+2002-08-19 Werner Koch <[email protected]>
+
+ * decrypt.c (is_token,skip_token): Duplicated from verify.c
+ (gpgme_op_decrypt): Hack to properly return Decryption_Failed..
+ (_gpgme_decrypt_status_handler): Create an operation info.
+
+2002-08-14 Werner Koch <[email protected]>
+
+ * key.h (struct certsig_s): New. Use it in gpgme_key_s.
+ * key.c (gpgme_key_release): Release it. We need to add more code
+ of course.
+ (_gpgme_key_append_name): Use memset to intialize the struct.
+ * gpgme.h (GPGME_KEYLIST_MODE_SIGS): New.
+ * rungpg.c (_gpgme_gpg_op_keylist): Include sigs in listing depending
+ non the list mode.
+
+ * key.c (gpgme_key_get_string_attr): Use GPGME_ATTR_TYPE to return
+ information about the key type (PGP or X.509).
+ (gpgme_key_get_ulong_attr): Likewise.
+
+ * keylist.c (keylist_colon_handler): Include 1 in the check for
+ valid algorithms so that RSA is usable. Store the issuer name and
+ serial number also for "crs" records. Parse the expire date for
+ subkeys.
+ (set_userid_flags): Put them onto the last appended key.
+
+2002-07-29 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_op_edit): Use --with-colons.
+
+2002-07-28 Marcus Brinkmann <[email protected]>
+
+ * data.c (gpgme_data_read): For GPGME_DATA_TYPE_NONE, return EOF
+ instead an error.
+
+ The following changes make it possible to flush an inbound data
+ pipe before invoking a command handler:
+
+ * posix-io.c (_gpgme_io_select): Accept new argument NONBLOCK to
+ _gpgme_io_select. Set timeout of 0 if this is set.
+ * w32-io.c (_gpgme_io_select): Likewise.
+ * io.h: Add new argument NONBLOCK to _gpgme_io_select prototype.
+ * wait.c (do_select): Add new argument to _gpgme_io_select
+ invocation.
+ * rungpg.h (_gpgme_gpg_set_command_handler): Add new argument
+ linked_data to prototype.
+ * engine.h (_gpgme_engine_set_command_handler): Likewise.
+ * engine.c (_gpgme_engine_set_command_handler): Likewise.
+ * passphrase.c (_gpgme_passphrase_start): Pass NULL as linked_data
+ argument to _gpgme_engine_set_command_handler.
+ * rungpg.c (struct gpg_object_s): New members linked_data and
+ linked_idx in CMD.
+ (_gpgme_gpg_new): Initialize those new members.
+ (_gpgme_gpg_set_command_handler): Accept new argument linked_data.
+ (build_argv): Handle linked_data in the same hack as cb_data.
+ (read_status): If linked_data is in use, flush the pipe before
+ activating the command handler.
+ * gpgme.h: Add prototypes for gpgme_op_edit_start and
+ gpgme_op_edit.
+
+ The next changes export the status codes to the user:
+
+ * decrypt.c (_gpgme_decrypt_status_handler): Likewise, also prefix
+ all STATUS_ with GPGME_.
+ * delete.c (delete_status_handler): Likewise.
+ * decrypt-verify.c (decrypt_verify_status_handler): Likewise.
+ * encrypt.c (_gpgme_encrypt_status_handler): Likewise.
+ (_gpgme_encrypt_sym_status_handler): Likewise.
+ * encrypt-sign.c (encrypt_sign_status_handler): Likewise.
+ * engine-gpgsm.c (parse_status): Likewise.
+ (gpgsm_status_handler): Likewise.
+ (gpgsm_set_recipients): Likewise.
+ * export.c (export_status_handler): Likewise.
+ * genkey.c (genkey_status_handler): Likewise.
+ * import.c (append_xml_impinfo): Likewise.
+ (import_status_handler): Likewise.
+ * keylist.c (keylist_status_handler): Likewise.
+ * passphrase.c (_gpgme_passphrase_status_handler): Likewise.
+ (command_handler): Likewise.
+ * progress.c (_gpgme_progress_status_handler): Likewise.
+ * sign.c (_gpgme_sign_status_handler): Likewise.
+ * trustlist.c (trustlist_status_handler): Likewise.
+ * verify.c (_gpgme_verify_status_handler): Likewise.
+ * gpgme.h (GpgmeEditCb): New type.
+ * rungpg.h (GpgStatusCode): Rename and move to ...
+ * gpgme.h (GpgmeStatusCode): ... this and here.
+ * Makefile.am (status-table.h): Run mkstatus on gpgme.h, not rungpg.h.
+ * mkstatus: Prefix STATUS with GPGME_.
+ * rungpg.h (GpgStatusHandler, GpgCommandHandler): Change type
+ accordingly.
+ * ops.h (_gpgme_verify_status_handler,
+ _gpgme_decrypt_status_handler, _gpgme_sign_status_handler,
+ _gpgme_encrypt_status_handler, _gpgme_passphrase_status_handler,
+ _gpgme_progress_status_handler): Likewise.
+ * rungpg.c (struct gpg_object_s): Likewise for CMD.code.
+
+ These changes add an edit operation to GPGME:
+
+ * context.h (struct gpgme_context_s): New member RESULT.edit. *
+ ops.h: Add prototype for _gpgme_release_edit_result and
+ _gpgme_passphrase_command_handler.
+ * passphrase.c (command_handler): Make non-static and rename to ...
+ (_gpgme_passphrase_command_handler): ... this.
+ (_gpgme_passphrase_start): Use new name for command handler.
+ * types.h: Add EditResult type.
+ * gpgme.c (_gpgme_release_result): Release EDIT result.
+ * edit.c: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add edit.c.
+ (libgpgme_la_LDADD): Rename to libgpgme_la_LIBADD, and include
+ assuan_libobjs.
+ (assuan_libobjs): New variable, set this instead
+ libgpgme_la_LIBADD.
+ * engine.h (_gpgme_engine_op_edit): New prototype.
+ * engine.c (_gpgme_engine_op_edit): New function.
+ * rungpg.h (_gpgme_gpg_op_edit): New prototype.
+ * rungpg.c (_gpgme_gpg_op_edit): New function.
+
+2002-07-27 Marcus Brinkmann <[email protected]>
+
+ * delete.c (delete_problem): New case ambigious specification.
+ (delete_status_handler): Handle new case (poorly).
+
+2002-07-25 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_delete): Implement this.
+
+2002-07-25 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (libgpgme_la_LDADD): Add @LIBOBJS@ for vasprintf and
+ fopencookie.
+ * vasprintf.c: Update to more recent libiberty version.
+ * debug.h: Replace #elsif with #elif.
+
+ Submitted by St�phane Corth�sy:
+ * util.h (vasprintf): Correct prototype.
+ * encrypt-sign.c: Include <stddef.h>.
+ (encrypt_sign_status_handler): Change type of ENCRYPT_INFO_LEN to
+ size_t.
+ * ath-pthread.c: Include <stdlib.h>, not <malloc.h>.
+ * ath-pth.c: Likewise.
+
+2002-07-25 Marcus Brinkmann <[email protected]>
+
+ * wait.c (fdt_global): Make static. Reported by St�phane
+ Corth�sy.
+
+ * rungpg.c (_gpgme_gpg_op_keylist_ext): Skip empty string
+ patterns. Reported by St�phane Corth�sy.
+
+ * key.c (gpgme_key_get_as_xml): Add OTRUST attribute. Requested
+ by St�phane Corth�sy.
+ (gpgme_key_get_string_attr): Add GPGME_ATTR_SIG_SUMMARY case to
+ silence gcc warning.
+
+ * rungpg.c (_gpgme_gpg_new): Always set utf8 as charset.
+
+2002-07-03 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_set_io_cbs): Deal with CTX being NULL.
+
+ * gpgme.c (_gpgme_op_event_cb_user): New function.
+ * op-support.c (_gpgme_op_reset): Support a new mode of operation
+ for private or user event loop. Use new user event callback
+ wrapper.
+ * trustlist.c (gpgme_op_trustlist_start): Use this new mode.
+ * keylist.c (gpgme_op_keylist_start): Likewise.
+
+ * rungpg.c (_gpgme_gpg_io_event): New function.
+ * rungpg.h (_gpgme_gpg_io_event): New prototype.
+ * engine-gpgsm.c (_gpgme_gpg_io_event): New function.
+ * engine-gpgsm.h (_gpgme_gpgsm_io_event): New prototype.
+ * engine.c (_gpgme_engine_io_event): New function.
+ * engine.h (_gpgme_engine_io_event): New prototype.
+ * keylist.c (finish_key): Call _gpgme_engine_io_event, and move
+ the real work for the default IO callback routines to ...
+ (_gpgme_op_keylist_event_cb): ... here. New function.
+ * trustlist.c (trustlist_colon_handler): Signal
+ GPGME_EVENT_NEXT_TRUSTITEM. Move queue manipulation to ...
+ (_gpgme_op_trustlist_event_cb): ... here. New function.
+ * gpgme.c (_gpgme_op_event_cb): Call _gpgme_op_keylist_event_cb
+ and _gpgme_op_trustlist_event_cb when appropriate.
+ * ops.h (_gpgme_op_keylist_event_cb): New prototype.
+ (_gpgme_op_trustlist_event_cb): Likewise.
+ * op-support.c (_gpgme_op_reset): Add comment why we don't use the
+ user provided event handler directly.
+ * gpgme.h (GpgmeRegisterIOCb): Return GpgmeError value, and TAG in
+ a pointer argument.
+ * wait.c (_gpgme_add_io_cb): Likewise.
+ * wait.h (_gpgme_add_io_cb): Likewise for prototype.
+ * rungpg.c (_gpgme_gpg_add_io_cb): Call IO_CBS->add with new
+ argument. Fix up error handling.
+ * engine-gpgsm.c (_gpgme_gpgsm_add_io_cb): Call IO_CBS->add with
+ new argument, fix up error handling.
+
+2002-07-03 Werner Koch <[email protected]>
+
+ * encrypt.c (status_handler_finish): New.
+ (_gpgme_encrypt_status_handler): Moved some code out to the new
+ function and call this function also in case we get into the
+ status handler with an error which might happen due to a kludge in
+ engine-gpgsm.c
+
+2002-06-28 Marcus Brinkmann <[email protected]>
+
+ * keylist.c (gpgme_op_keylist_ext_start): Always use our own FD
+ table (eg use synchronous mode).
+
+2002-06-28 Marcus Brinkmann <[email protected]>
+
+ * ops.h (_gpgme_wait_on_condition): Remove HANG argument from
+ prototype and change return type to GpgmeError.
+ (_gpgme_wait_one): New prototype.
+ * wait.c (gpgme_wait): Replace with the meat from
+ _gpgme_wait_on_condition here, and remove the support for
+ conditions.
+ (_gpgme_wait_on_condition): Remove HANG argument from prototype
+ and change return type to GpgmeError. Replace with meat from
+ _gpgme_wait_one and add support for conditions.
+ (_gpgme_wait_one): Just call _gpgme_wait_on_condition without
+ condition.
+ * keylist.c (gpgme_op_keylist_ext_start): Always use our own FD
+ table (eg use synchronous mode).
+ (gpgme_op_keylist_next): Remove HANG argument from
+ _gpgme_wait_on_condition. Check its return value.
+ * trustlist.c (gpgme_op_trustlist_start): Always use our own FD
+ table (eg use synchronous mode).
+ (gpgme_op_trustlist_next): Remove HANG argument from
+ _gpgme_wait_on_condition. Check its return value.
+
+2002-06-27 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Fix documentation of key attribute retrieval functions.
+
+2002-06-26 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (map_assuan_error): Map No_Data_Available to EOF.
+
+ * import.c (append_xml_impinfo): Kludge to print fingerprint
+ instead of keyid for use with gpgsm.
+ (import_status_handler): Set a flag to know whether any import
+ occured.
+ (gpgme_op_import): Reurn -1 if no certificate ewas imported.
+
+2002-06-25 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_set_io_cbs) [ENABLE_GPGSM]: Fixed
+ function arguments.
+
+2002-06-25 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_export): Only export the keys
+ listed in RECP.
+ * export.c (gpgme_op_export): If no data was returned, return
+ GPGME_No_Recipients.
+
+2002-06-25 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_export): Implement.
+
+2002-06-21 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_assuan_simple_command): Return ERR.
+ (parse_status): New function.
+ (gpgsm_status_handler): Use parse_status.
+ (gpgsm_assuan_simple_command): Accept new arguments STATUS_FNC and
+ STATUS_FNC_VALUE and process status messages.
+ (gpgsm_set_recipients): Pass new arugments to gpgsm_assuan_simple_command.
+ (gpgsm_set_fd): Likewise.
+ (_gpgme_gpgsm_op_keylist): Likewise.
+ (_gpgme_gpgsm_op_keylist_ext): Likewise.
+ (_gpgme_gpgsm_op_sign): Likewise.
+
+2002-06-21 Marcus Brinkmann <[email protected]>
+
+ * wait.c (_gpgme_remove_io_cb): Unlock FDT->lock.
+
+2002-06-20 Werner Koch <[email protected]>
+
+ * rungpg.c (build_argv): Ignore GPG_AGENT_INFO if set but empty.
+
+ * verify.c (calc_sig_summary): Set bad policy for wrong key usage.
+ (skip_token): New.
+ (_gpgme_verify_status_handler): Watch out for wrong key usage.
+ (gpgme_get_sig_string_attr): Hack to return info on the key
+ usage. Does now make use of the former RESERVED argument which
+ has been renamed to WHATIDX.
+ (gpgme_get_sig_ulong_attr): Renamed RESERVED to WHATIDX.
+
+2002-06-14 Marcus Brinkmann <[email protected]>
+
+ * wait.c (do_select): Return -1 on error, and 0 if nothing to run.
+ (_gpgme_wait_one): Only set HANG to zero if do_select returned an
+ error, or there are no more file descriptors to wait on.
+ (_gpgme_wait_on_condition): Ignore return value from do_select for
+ now.
+
+2002-06-13 Werner Koch <[email protected]>
+
+ * verify.c (gpgme_op_verify): Make sure that we never access an
+ unitialized result structure.
+
+2002-06-12 Werner Koch <[email protected]>
+
+ * keylist.c (struct keylist_result_s): New.
+ (_gpgme_release_keylist_result): Release it here
+ (keylist_status_handler): Handle truncated.
+ (append_xml_keylistinfo): New.
+ * gpgme.c (_gpgme_release_result): and use it here.
+ * types.h: Declare the new type here.
+ * context.h (struct gpgme_context_s): Use it here.
+
+2002-06-11 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_release): Close status_cb.fd.
+ (_gpgme_gpgsm_new): Duplicate status file descriptor, so we can
+ use our own close notification mechanism without interfering with
+ assuan.
+
+2002-06-11 Werner Koch <[email protected]>
+
+ * gpgme.h: Add GPGME_ATTR_SIG_SUMMARY and the GPGME_SIGSUM_
+ constants.
+ * verify.c (calc_sig_summary): New.
+ (gpgme_get_sig_ulong_attr): And use it here.
+
+2002-06-10 Werner Koch <[email protected]>
+
+ * rungpg.h: Add new status codes TRUNCATED and ERROR.
+ * verify.c (is_token, copy_token): New.
+ (_gpgme_verify_status_handler): Use copy_token, handle the new
+ ERROR status and store the errorcode used withgpgsm and trust
+ status codes.
+ * gpgme.h: New attribute ERRTOK.
+ * key.c (gpgme_key_get_string_attr): Add dummy case for it.
+ (gpgme_get_sig_string_attr): Use it here to return the last error.
+
+2002-06-10 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_start): Move the code that sets the
+ close notification for the status fd to ...
+ (_gpgme_gpgsm_new): ... here.
+ * wait.h: Include "sema.h". Remove prototypes of
+ _gpgme_remove_proc_from_wait_queue and
+ _gpgme_register_pipe_handler. Add prototypes of
+ _gpgme_fd_table_init, _gpgme_fd_table_deinit, _gpgme_fd_table_put,
+ _gpgme_add_io_cb, _gpgme_remove_io_cb, _gpgme_wait_event_cb and
+ _gpgme_wait_one..
+ * wait.c: Remove global variables PROC_QUEUE, PROC_QUEUE_LOCK,
+ FD_TABLE_SIZE, FD_TABLE, FD_TABLE_LOCK. New global variables
+ FDT_GLOBAL, CTX_DONE_LIST, CTX_DONE_LIST_SIZE,
+ CTX_DONE_LIST_LENGTH and CTX_DONE_LIST_LOCK. Remove struct
+ proc_s. Replace struct wait_item_s.
+ (_gpgme_fd_table_init): New function.
+ (_gpgme_fd_table_deinit): Likewise.
+ (_gpgme_fd_table_put): Likewise.
+ (set_process_done): Remove function.
+ (do_select): Take argument FDT. Use that to decide which fds to
+ select on.
+ (_gpgme_remove_proc_from_wait_queue): Remove function.
+ (_gpgme_wait_event_cb): New function.
+ (_gpgme_wait_one): Likewise.
+ (_gpgme_register_pipe_hanldler): Remove function.
+ (_gpgme_add_io_cb): New function.
+ (_gpgme_remove_io_cb): Likewise.
+ (_gpgme_freeze_fd): Remove function.
+ (_gpgme_thaw_fd): Remove function.
+ * rungpg.c (struct fd_data_map_s): Add new member TAG.
+ (struct gpg_object_s): Likewise for STATUS and COLON. Add member
+ IDX to CMD. Add new member IO_CBS.
+ (close_notify_handler): New variables POSSIBLY_DONE and NOT_DONE.
+ For each I/O callback, check if it should be unregistered. If all
+ callbacks have been unregistered, trigger GPGME_EVENT_DONE.
+ Remove member RUNNING.
+ (_gpgme_gpg_new): Initialize new members.
+ (_gpgme_gpg_release): Check PID not RUNNING. Don't call
+ _gpgme_remove_proc_from_wait_queue. Close GPG->CMD.FD if set.
+ (build_argv): Store away the index instead the file descriptor for
+ CMD.
+ (_gpgme_gpg_add_io_cb): New function.
+ (_gpgme_gpg_spawn): Use _gpgme_gpg_add_io_cb to register IO
+ callbacks.
+ (gpg_status_handler): Change return type to void, remove PID
+ argument, close filedescriptor if EOF or error occurs.
+ (read_status): Use _gpgme_gpg_add_io_cb instead _gpgme_thaw_fd.
+ Use IO_CBS->remove instead _gpgme_freeze_fd.
+ (gpg_colon_line_handler): Change return type to void, remove PID
+ argument, close filedescriptor if EOF or error occurs.
+ (command_cb): Use IO_CBS->remove instead _gpgme_freeze_fd.
+ (_gpgme_gpg_set_io_cbs): New function.
+ * rungpg.h (_gpgme_gpg_set_io_cbs): Prototype for
+ _gpgme_gpg_set_io_cbs.
+ * gpgme.h (GpgmeIOCb): New type.
+ (GpgmeRegisterIOCb): Likewise.
+ (GpgmeRemoveIOCb): Likewise.
+ (GpgmeEventIO): Likewise.
+ (GpgmeEventIOCb): Likewise.
+ (struct GpgmeIOCbs): New structure to hold I/O callbacks.
+ (gpgme_set_op_io_cbs): New prototype.
+ (gpgme_get_op_io_cbs): Likewise.
+ * ops.h: New prototype for _gpgme_op_event_cb. Remove prototypes
+ for _gpgme_freeze_fd and _gpgme_thaw_fd. Remove PID argument from
+ _gpgme_data_inbound_handler and _gpgme_data_outbound_handler
+ prototype. Add prototype for _gpgme_op_reset.
+ Add synchronous argument to _gpgme_decrypt_start prototype.
+ * io.h: Beautification.
+ * gpgme.c: Include "wait.h".
+ (gpgme_new): Initialize FDT.
+ (gpgme_set_io_cbs): New function.
+ (gpgme_get_io_cbs): Likewise.
+ (_gpgme_op_event_cb): Likewise.
+ * data.c (_gpgme_data_inbound_handler): Change return type to
+ void. Drop PID argument. Close FD on error and EOF.
+ (write_mem_data): Don't close FD here ...
+ (write_cb_data): ... or here ...
+ (_gpgme_data_outbound_handler): ... but here. Change return type
+ to void. Drop PID argument.
+ * context.h: Include "wait.h".
+ (struct gpgme_context_s): New members FDT and IO_CBS.
+ * op-support.c: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add op-support.c.
+ * ops.h: Add prototype for _gpgme_op_reset().
+ * decrypt.c (_gpgme_decrypt_start): New argument SYNCHRONOUS. Use
+ _gpgme_op_reset.
+ (gpgme_op_decrypt_start): Add synchronous argument.
+ (gpgme_op_decrypt): Likewise. Use _gpgme_wait_one instead
+ gpgme_wait.
+ * delete.c (gpgme_op_delete_start): Rename to ...
+ (_gpgme_op_delete_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_delete_start): Just a wrapper around
+ _gpgme_op_delete_start now.
+ (gpgme_op_delete): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * encrypt.c: Include "wait.h".
+ (ggpgme_op_encrypt_start): Rename to ...
+ (_gpgme_op_encrypt_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_encrypt_start): Just a wrapper around
+ _gpgme_op_encrypt_start now.
+ (gpgme_op_encrypt): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * encrypt_sign.c (gpgme_op_encrypt_sign_start): Rename to ...
+ (_gpgme_op_encrypt_sign_start): ... this. New argument
+ SYNCHRONOUS. Use _gpgme_op_reset. Make function static.
+ (gpgme_op_encrypt_sign_start): Just a wrapper around
+ _gpgme_op_encrypt_sign_start now.
+ (gpgme_op_encrypt_sign): Add synchronous argument. Use
+ _gpgme_wait_one instead gpgme_wait.
+ * export.c (gpgme_op_export_start): Rename to ...
+ (_gpgme_op_export_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_export_start): Just a wrapper around
+ _gpgme_op_export_start now.
+ (gpgme_op_export): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * genkey.c (gpgme_op_genkey_start): Rename to ...
+ (_gpgme_op_genkey_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_genkey_start): Just a wrapper around
+ _gpgme_op_genkey_start now.
+ (gpgme_op_genkey): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * import.c (gpgme_op_import_start): Rename to ...
+ (_gpgme_op_import_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_import_start): Just a wrapper around
+ _gpgme_op_import_start now.
+ (gpgme_op_import): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * keylist.c (gpgme_op_keylist_start): Use _gpgme_op_reset.
+ (gpgme_op_keylist_ext_start): Likewise.
+ * sign.c (gpgme_op_sign_start): Rename to ...
+ (_gpgme_op_sign_start): ... this. New argument SYNCHRONOUS. Use
+ _gpgme_op_reset. Make function static.
+ (gpgme_op_sign_start): Just a wrapper around _gpgme_op_sign_start
+ now.
+ (gpgme_op_sign): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * trustlist.c (gpgme_op_trustlist_start): Use _gpgme_op_reset.
+ * verify.c (gpgme_op_verify_start): Rename to ...
+ (_gpgme_op_verify_start): ... this. New argument SYNCHRONOUS.
+ Use _gpgme_op_reset. Make function static.
+ (gpgme_op_verify_start): Just a wrapper around
+ _gpgme_op_verify_start now.
+ (gpgme_op_verify): Add synchronous argument. Use _gpgme_wait_one
+ instead gpgme_wait.
+ * engine-gpgsm.c (iocb_data_t): New type.
+ (struct gpgsm_object_s): New member status_cb. Replace input_fd
+ and input_data with input_cb. Replace output_fd and output_data
+ with output_cb. Replace message_fd and message_data with
+ message_cb. New member io_cbs.
+ (_gpgme_gpgsm_new): Initialize all new members (and drop the old
+ ones).
+ (close_notify_handler): New variable POSSIBLY_DONE. For each I/O
+ callback, check if it should be unregistered. If all callbacks
+ have been unregistered, trigger GPGME_EVENT_DONE.
+ (_gpgme_gpgsm_release): Remove variable PID. Use new variable
+ names to close the file descriptors.
+ (_gpgme_gpgsm_op_decrypt): Use new variable names,
+ (_gpgme_gpgsm_op_encrypt): Likewise.
+ (_gpgme_gpgsm_op_genkey): Likewise.
+ (_gpgme_gpgsm_op_import): Likewise.
+ (_gpgme_gpgsm_op_keylist): Likewise.
+ (_gpgme_gpgsm_op_keylist_ext): Likewise.
+ (_gpgme_gpgsm_op_sign): Likewise.
+ (_gpgme_gpgsm_op_verify): Likewise.
+ (gpgsm_status_handler): Drop argument PID. Change return type to
+ void. Close status pipe before returning because of EOF or error.
+ (_gpgme_gpgsm_add_io_cb): New function.
+ (_gpgme_gpgsm_start): Use _gpgme_gpgsm_add_io_cb to register
+ callback function.
+ (_gpgme_gpgsm_set_io_cbs): New function.
+ * engine-gpgsm.h: New prototype for _gpgme_gpgsm_set_io_cbs.
+ * engine.c (_gpgme_engine_set_io_cbs): New function.
+ * engine.h: New prototype for _gpgme_engine_set_io_cbs.
+
+2002-06-04 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (libgpgme_la_SOURCES): Remove mutex.h.
+
+2002-06-03 Marcus Brinkmann <[email protected]>
+
+ * key.c: Include <ctype.h>.
+ (_gpgme_key_append_name): Skip one more char when
+ processing escaped char. Submitted by Marc Mutz <[email protected]>.
+ Handle hexadecimal encodings. Also reported by Marc. Thanks!
+
+2002-06-02 Marcus Brinkmann <[email protected]>
+
+ * ath.h: Enable the _gpgme_ prefix. Fix all those prefix macros.
+ * posix-sema.c: Use that prefix here.
+ * posix-io.c: Include "ath.h".
+ (_gpgme_io_read): Use _gpgme_ath_read instead read.
+ (_gpgme_io_write): Use _gpgme_ath_write instead write.
+ (_gpgme_io_waitpid): Use _gpgme_ath_waitpid instead waitpid.
+ (_gpgme_io_select): Use _gpgme_ath_select instead select.
+
+2002-06-02 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (ath_components): New variable.
+ (ath_components_pthread): Likewise.
+ (ath_components_pth): Likewise.
+ (system_components): Add ath_componentes.
+
+ * ath.h: New file.
+ * ath.c: Likewise.
+ * ath-pthread.c: Likewise.
+ * ath-pth.c: Likewise.
+ * posix-sema.c (_gpgme_sema_cs_enter): Rework to use the ATH
+ interface.
+ * mutex.h: Remove file.
+
+2002-05-30 Werner Koch <[email protected]>
+
+ * key.c (gpgme_key_get_string_attr): Return NULL when asking for
+ an issuer with IDX > 0. We don't support altIssuerNames for now.
+
+2002-05-22 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext): Aehmm, added
+ missing variable definition. Oohh - Marcus was faster.
+
+2002-05-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext): Fix last change.
+
+2002-05-21 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist)
+ (_gpgme_gpgsm_op_keylist_ext): Pass the keylist mode to gpgsm.
+
+2002-05-10 Werner Koch <[email protected]>
+
+ * key.h (gpgme_key_s): Add OTRUST.
+ * keylist.c (set_ownertrust): New.
+ (keylist_colon_handler): Get the ownertrust value
+ * key.c (gpgme_key_get_string_attr,gpgme_key_get_ulong_attr):
+ Return that value.
+
+2002-05-08 Marcus Brinkmann <[email protected]>
+
+ * w32-util.c: New static variable GET_PATH_LOCK.
+ (_gpgme_get_gpg_path): Remove superfluous NULL initializer.
+ Take lock while determining path.
+ (_gpgme_get_gpgsm_path): Likewise.
+ * version.c (do_subsystem_inits): Set DONE to 1 after
+ initialization.
+ (gpgme_get_engine_info): New variable ENGINE_INFO_LOCK. Take lock
+ while determining engine info.
+ * rungpg.c (_gpgme_gpg_get_version): New variable
+ GPG_VERSION_LOCK. Take the lock while determining the program
+ version.
+ * posix-io.c: Include "sema.h".
+ (_gpgme_io_spawn): New variable FIXED_SIGNALS_LOCK. Take the lock
+ while fixing the signals.
+ (_gpgme_io_select): Make READFDS and WRITEFDS non-static.
+ * key.c: Include "sema.h". New globals KEY_CACHE_LOCK and
+ KEY_REF_LOCK.
+ (capabilities_to_string): Make STRINGS very const.
+ (_gpgme_key_cache_add): Lock the key cache.
+ (_gpgme_key_cache_get): Likewise.
+ (gpgme_key_ref, gpgme_key_release): Lock the key_ref_lock.
+ * import.c (append_xml_impinfo): Make IMPORTED_FIELDS and
+ IMPORT_RES_FIELDS very const. Make FIELD and FIELD_NAME a litle
+ const.
+ * engine.c (_gpgme_engine_get_info): New variable
+ ENGINE_INFO_LOCK. Take lock while determining engine info.
+ * engine-gpgsm.c: Include "sema.h".
+ (_gpgme_gpgsm_get_version): New variable GPGSM_VERSION_LOCK. Take
+ lock while getting program version.
+
+2002-05-08 Marcus Brinkmann <[email protected]>
+
+ * debug.h: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add debug.h.
+ * util.h: Removed all prototypes and declarations related to
+ debugging. Include "debug.h".
+
+ * debug.c (debug_level): Comment variable and remove superfluous
+ zero initializer.
+ (errfp): Likewise.
+ (_gpgme_debug_enabled): Function removed.
+ (struct debug_control_s): Definition removed.
+ (_gpgme_debug_level): Function removed.
+ (_gpgme_debug_begin): Rewritten to use vasprintf. Accept a
+ pritnf-style format specification and a variable number of
+ arguments.
+ (_gpgme_debug_add): Rewritten using vasprintf. Expect that format
+ starts out with "%s" for simplicity.
+ (_gpgme_debug_end): Rewritten using vasprintf. Do not accept a
+ TEXT argument anymore.
+
+ * posix-io.c (_gpgme_io_select): Use new level argument for
+ DEBUG_BEGIN instead explicit if construct.
+
+ * debug.c (debug_init): Remove superfluous zero initializer,
+ remove volatile flag of INITIALIZED. Do not use the
+ double-checked locking algorithm, it is fundamentally flawed and
+ will empty your fridge (on a more serious note, despite the
+ volatile flag it doesn't give you the guarantee you would expect,
+ for example on a DEC Alpha or an SMP machine. The volatile only
+ serializes accesses to the volatile variable, but not to the other
+ variables).
+
+2002-05-03 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): Redirect any gpgsm error
+ output to /dev/null.
+
+ * verify.c (gpgme_get_sig_key): Set the protocol of the listctx.
+ * gpgme.c (gpgme_get_protocol): New.
+
+ * data.c (gpgme_data_write): Changed type of BUFFER to void*.
+ (gpgme_data_read): Ditto.
+
+ * verify.c (_gpgme_verify_status_handler): Handle TRUST_* status
+ lines so that a claim can be made without looking up the key.
+ (gpgme_get_sig_string_attr): New.
+ (gpgme_get_sig_ulong_attr): New.
+
+ * gpgme.h (GpgmeAttr): Added GPGME_ATTR_SIG_STATUS.
+
+ * rungpg.h: Add new status codes from gpg 1.0.7 and formatted the
+ list to align with the status.h file from gnupg.
+
+ * gpgme.h (GpgmeSigStat): Add _GOOD_EXP and _GOOD_EXPKEY.
+ * verify.c (_gpgme_verify_status_handler, finish_sig): Handle
+ these new status codes. Store the expiration time
+
+2002-04-27 Werner Koch <[email protected]>
+
+ * gpgme.h (GpgmeData_Encoding): New.
+ * data.c (gpgme_data_get_encoding,gpgme_data_set_encoding): New.
+ * engine-gpgsm.c (map_input_enc): New. Use it in all local
+ functions where the INPUT command gets send.
+
+2002-04-27 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_verify): Close the output
+ descriptor only when we don't need it anymore. Close the message
+ descriptor if we don't need it.
+
+2002-04-26 Werner Koch <[email protected]>
+
+ * Makefile.am (libgpgme_la_LIBADD): Use libtool libraries.
+
+2002-04-25 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_release): Call gpgme_data_release on
+ GPG->cmd.cb_data, not xfree.
+
+2002-04-25 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): Set the display, ttyname,
+ ttytype, lc_ctype and lc_messages options in the server.
+
+2002-04-24 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (map_assuan_error): Add new error codes.
+
+2002-04-23 Werner Koch <[email protected]>
+
+ * key.c (gpgme_key_get_ulong_attr): Swapped use of can_encrypt and
+ can_certify to return the requested values.
+
+2002-04-23 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_get_progress_cb): Allow either return parameter
+ to be NULL.
+ (gpgme_get_passphrase_cb): Likewise.
+
+2002-04-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_get_passphrase_cb): New function.
+ (gpgme_get_progress_cb): New function.
+ * gpgme.h: Add new prototypes for gpgme_get_passphrase_cb and
+ gpgme_get_progress_cb.
+
+2002-03-28 Werner Koch <[email protected]>
+
+ * gpgme.h (GpgmeAttr): Add values for issuer and chaining.
+ * key.h (gpgme_key_s): Add issuer and chaining elements for X509.
+ * keylist.c (keylist_colon_handler): Store them.
+ * key.c (gpgme_key_release): Free them.
+ (gpgme_key_get_as_xml,gpgme_key_get_string_attr): Print them.
+
+2002-03-26 Werner Koch <[email protected]>
+
+ * Makefile.am (libgpgme_la_SOURCES): Add mutex.h
+
+2002-03-21 Werner Koch <[email protected]>
+
+ * util.h [!HAVE_FOPENCOOKIE]: Make sure off_t and ssize_t are
+ defined.
+
+2002-03-18 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (system_components): New variable, set depending on
+ HAVE_DOSISH_SYSTEM.
+ (libgpgme_la_SOURCES): Use system_components. Remove `syshdr.h'.
+ * syshdr.h: File removed.
+
+ * posix-io.c: Remove !HAVE_DOSISH_SYSTEM safeguard. Clean up source.
+ * posix-sema.c: Likewise.
+ * posix-util.c: Likewise.
+
+ * w32-io.c: Remove HAVE_DOSISH_SYSTEM safeguard.
+ * w32-sema.c: Likewise.
+ * w32-util.c: Likewise.
+
+ * posix-io.c: Include `unistd.h', do not include `syshdr.h'.
+ * posix-sema.c: Likewise.
+ * w32-io.c: Include `io.h', do not include `syshdr.h'
+ * w32-sema.c: Likewise.
+ * w32-util.c: Likewise.
+ * data.c: Do not include `syshdr.h'.
+ * wait.c: Likewise.
+ * wait.h: Code cleanup.
+
+ * mutex.h: New file.
+ * posix-sema.c: Implement.
+
+2002-03-08 Werner Koch <[email protected]>
+
+ * util.h [!HAVE_FOPENCOOKIE]: Fixed type. Thanks to Frank Heckenbach.
+
+2002-03-07 Werner Koch <[email protected]>
+
+ * gpgme.h (gpgme_op_keylist_ext_start): Add prototype.
+
+2002-03-06 Marcus Brinkmann <[email protected]>
+
+ * encrypt.c (_gpgme_encrypt_sym_status_handler): New function.
+ (gpgme_op_encrypt_start): New variable SYMMETRIC, set it if RECP
+ is null, and if it is set, use _gpgme_encrypt_sym_status_handler
+ as status handler and run _gpgme_passphrase_start.
+ * rungpg.c (_gpgme_gpg_op_encrypt): If RECP is zero, do symmetric
+ encryption.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_encrypt): If RECP is zero,
+ return error value.
+
+ * rungpg.c (_gpgme_gpg_op_verify): Add "--" argument.
+
+2002-03-03 Marcus Brinkmann <[email protected]>
+
+ * passphrase.c (_gpgme_passphrase_status_handler): Also set the
+ error No_Passphrase if only a bad passphrase was provided.
+
+2002-03-03 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_op_verify): If TEXT is of mode
+ GPGME_DATA_MODE_IN, construct a command line that stores the
+ plaintext in TEXT.
+ * verify.c (gpgme_op_verify_start): Accept TEXT being
+ uninitialized, and in this case interpret SIG as a normal or
+ cleartext signature and TEXT as a return data object.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_verify): Likewise.
+
+2002-03-03 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext) [!ENABLE_GPGSM]:
+ Add stub function.
+
+2002-02-28 Werner Koch <[email protected]>
+
+ * key.h (subkey_s): New member expires_at.
+ * keylist.c (keylist_colon_handler): Set it here
+ * key.c (gpgme_key_get_as_xml,gpgme_key_get_ulong_attr): Return it.
+
+2002-02-27 Marcus Brinkmann <[email protected]>
+
+ * rungpg.h (_gpgme_gpg_op_keylist_ext): New prototype.
+ * rungpg.c (_gpgme_gpg_op_keylist_ext): New function.
+ * engine-gpgsm.h (_gpgme_gpgsm_op_keylist_ext): New prototype.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext): New function.
+ * engine.h (_gpgme_engine_op_keylist_ext): New prototype.
+ * engine.c (_gpgme_engine_op_keylist_ext): New function.
+ * keylist.c (gpgme_op_keylist_ext_start): New function.
+
+2002-02-27 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add new error code GPGME_Invalid_Recipient.
+ * encrypt.c (struct encrypt_result_s): New member invalid_recipients,
+ rename no_recipients to no_valid_recipients.
+ (_gpgme_encrypt_status_handler): Include error for invalid
+ recipients.
+ * engine-gpgsm.c (gpgsm_set_recipients): Change type of first
+ argument to GpgsmObject. Use that to report back the status about
+ the recipients.
+
+2002-02-26 Marcus Brinkmann <[email protected]>
+
+ * verify.c (_gpgme_verify_status_handler): Fix the last change.
+
+2002-02-25 Marcus Brinkmann <[email protected]>
+
+ * engine.c (_gpgme_engine_op_encrypt_sign): New function.
+ * engine.h (_gpgme_engine_op_encrypt_sign): New prototype.
+ * rungpg.c (_gpgme_append_gpg_args_from_signers): New function.
+ (_gpgme_gpg_op_sign): Use that new function.
+ (_gpgme_gpg_op_encrypt_sign): New function.
+ * rungpg.h (_gpgme_gpg_op_encrypt_sign): New prototype.
+ * gpgme.h (gpgme_op_encrypt_sign_start): New prototype.
+ (gpgme_op_encrypt_sign): Likewise.
+ * Makefile.am (libgpgme_la_SOURCES): Add encrypt-sign.c.
+ * ops.h (_gpgme_encrypt_status_handler): Add prototype.
+ (_gpgme_sign_status_handler): Add prototype.
+ * sign.c (sign_status_handler): Rename to ...
+ (_gpgme_sign_status_handler): ... this and make non-static.
+ * encrypt.c (encrypt_status_handler): Rename to ...
+ (_gpgme_encrypt_status_handler): ... this and make non-static.
+ * encrypt.c (gpgme_op_encrypt_start): Use new status handler name.
+ * sign.c (gpgme_op_sign_start): Likewise.
+
+2002-02-25 Marcus Brinkmann <[email protected]>
+
+ * verify.c (_gpgme_verify_status_handler): Parse the args line to
+ see if the problem is due to a missing key, and report that back
+ to the user.
+
+2002-02-25 Marcus Brinkmann <[email protected]>
+
+ * context.h (struct gpgme_context_s): New member include_certs.
+ * gpgme.h (gpgme_set_include_certs): Add prototype.
+ (gpgme_get_include_certs): Likewise.
+ * gpgme.c (gpgme_set_include_certs): New function.
+ (gpgme_get_include_certs): Likewise.
+ (gpgme_new): Set include_certs to 1 (the default).
+ * engine.c (_gpgme_engine_op_sign): Accept new argument include_certs,
+ and pass it to _gpgme_gpgsm_op_sign.
+ * engine.h (_gpgme_engine_op_sign): Likewise for prototype.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Accept new argument
+ include_certs and handle it.
+ * engine-gpgsm.h (_gpgme_gpgsm_start): Add new argument include_certs.
+ * sign.c (gpgme_op_sign_start): Add new argument to
+ _gpgme_engine_op_sign call.
+
+2002-02-14 Werner Koch <[email protected]>
+
+ * keylist.c (gpgme_op_keylist_start): Do not use a verbose listing.
+
+2002-02-13 Werner Koch <[email protected]>
+
+ * vasprintf.c, fopencookie.c: Add replacement functions.
+ * util.h: Add prototypes for them.
+
+2002-02-09 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_assuan_simple_command): Return 0 if we
+ reach the end of the function.
+
+2002-02-09 Marcus Brinkmann <[email protected]>
+
+ * genkey.c (gpgme_op_genkey_start): Fix logic in validity check.
+ (gpgme_op_genkey_start): Skip newlines after opening tag.
+
+ * engine-gpgsm.c (_gpgme_gpgsm_start): Remove cruft.
+
+2002-02-08 Marcus Brinkmann <[email protected]>
+
+ * genkey.c (gpgme_op_genkey_start): Allow PUBKEY and SECKEY to be
+ set, and pass them down to the crypto engine.
+ * engine-gpgsm.h (_gpgme_gpgsm_start): New arguments PUBKEY and SECKEY.
+ * engine.h: Likewise.
+ * rungpg.h (_gpgme_gpg_spawn): Likewise.
+ * engine.c (_gpgme_engine_op_genkey): Likewise. Use those
+ arguments.
+ * rungpg.c (_gpgme_gpg_op_genkey): Likewise. Complain if those
+ arguments are set.
+ * engine-gpgsm.c (_gpgme_gpgsm_op_genkey): Likewise. Implement
+ function.
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist): Beautify comment.
+
+2002-02-06 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_op_keylist): Remove handling of keylist
+ mode (for now).
+
+2002-02-06 Marcus Brinkmann <[email protected]>
+
+ * wait.c (gpgme_wait): Add new argument STATUS, in which the
+ status of the returned context is returned.
+ (_gpgme_wait_on_condition): Rework the function a bit, to make it
+ aware of cancelled processes, and to allow to use gpgme_wait with
+ CTX being NULL (as documented in the source).
+ (struct proc_s): New member REPORTED.
+ * gpgme.h: Fix prototype.
+ * verify.c (gpgme_op_verify): Fix use of gpgme_wait.
+ * sign.c (gpgme_op_sign): Likewise.
+ * import.c (gpgme_op_import): Likewise.
+ * genkey.c (gpgme_op_genkey): Likewise.
+ * export.c (gpgme_op_export): Likewise.
+ * encrypt.c (gpgme_op_encrypt): Likewise.
+ * delete.c (gpgme_op_delete): Likewise.
+ * decrypt-verify.c (gpgme_op_decrypt_verify): Likewise.
+
+2002-02-06 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_set_keylist_mode): Possibly return an error
+ value.
+ (gpgme_get_keylist_mode): New function.
+ (gpgme_new): Set the default for keylist_mode member of CTX.
+
+ * gpgme.h (gpgme_set_keylist_mode): Fix prototype.
+ (gpgme_get_keylist_mode): New prototype.
+ (GPGME_KEYLIST_MODE_LOCAL): New macro.
+ (GPGME_KEYLIST_MODE_EXTERN): Likewise..
+
+2002-02-02 Marcus Brinkmann <[email protected]>
+
+ This patch has gotten a bit large... mmh. The main thing that
+ happens here is that error values are now not determined in the
+ operation function after gpgme_wait completed, but in the status
+ handler when EOF is received. It should always be the case that
+ either an error is flagged or EOF is received, so that after a
+ gpgme_wait you should never have the situation that no error is
+ flagged and EOF is not received. One problem is that the engine
+ status handlers don't have access to the context, a horrible
+ kludge works around this for now. All errors that happen during a
+ pending operation should be catched and reported in ctx->error,
+ including out-of-core and cancellation. This rounds up neatly a
+ couple of loose ends, and makes it possible to pass up any errors
+ in the communication with the backend as well. As a bonus, there
+ will be a function to access gpgme->wait, so that the operations
+ can truly be implemented with their _start function.
+
+ * engine-gpgsm.c (gpgsm_status_handler): Horrible kludge to report
+ error back to the context.
+ * rungpg.c (gpg_status_handler): Same horrible kludge applied here.
+
+ * engine-gpgsm.c (gpgsm_assuan_simple_command): Add error checking.
+
+ * wait.c (_gpgme_wait_on_condition): If canceled, set CTX->error
+ to a value indication that.
+
+ * verify.c (add_notation): Set error, not out_of_core.
+ (finish_sig): Likewise.
+ (gpgme_op_verify_start): Don't clear out_of_core.
+ (_gpgme_verify_status_handler): At EOF, clean up the notation data.
+ (gpgme_op_verify): And don't do it here.
+
+ * trustlist.c (trustlist_status_handler): Check error, not out_of_core.
+ (gpgme_op_trustlist_start): Don't clear out_of_core.
+ (gpgme_op_trustlist_next): Check error, not out_of_core.
+ (gpgme_op_trustlist_end): Likewise.
+
+ * ops.h (test_and_allocate_result): New macro.
+ (_gpgme_passphrase_result): Remove prototype.
+ * delete.c (gpgme_op_delete): Return error from context.
+ (delete_status_handler): Use macro test_and_allocate_result.
+ Perform error checking at EOF.
+ (gpgme_op_delete_start): Release result.
+ * passphrase.c (_gpgme_passphrase_status_handler): Use macro
+ test_and_allocate_result, and perform error checking here.
+ (_gpgme_passphrase_result): Function removed.
+ * sign.c (gpgme_op_sign_start): Do not set out_of_core to zero.
+ (gpgme_op_sign): Just return the error value from the context.
+ (sign_status_handler): Only progress if no error is set yet. If
+ we process an EOF, set the resulting error value (if any).
+ * decrypt.c (_gpgme_decrypt_result): Function removed.
+ (create_result_struct): Function removed.
+ (_gpgme_decrypt_status_handler): Use macro test_and_allocate_result,
+ caclulate error on EOF, do not progress with errors.
+ (_gpgme_decrypt_start): Do not set out_of_core to zero.
+ (gpgme_op_decrypt): Just return the error value from the context.
+ * encrypt.c (encrypt_status_handler): Perform the error checking
+ here.
+ (gpgme_op_encrypt_start): Do not clear out_of_core.
+ * export.c (export_status_handler): Return if error is set in context.
+ (gpgme_op_export_start): Release result.
+ (gpgme_op_export): Return error from context.
+ * decrypt-verify.c (gpgme_op_decrypt_verify): Return the error in
+ the context.
+ * genkey.c (genkey_status_handler): Use macro
+ test_and_allocate_result. Perform error checking at EOF.
+ (gpgme_op_genkey): Just return the error from context.
+ * import.c (gpgme_op_import): Return the error from context.
+ (import_status_handler): Use macro test_and_allocate_result.
+ * keylist.c (gpgme_op_keylist_start): Do not clear out_of_core.
+ (gpgme_op_keylist_next): Return error of context.
+ (keylist_colon_handler): Set error instead out_of_code.
+ (finish_key): Likewise.
+
+ * context.h: Remove member out_of_core, add member error.
+ * gpgme.c (_gpgme_release_result): Clear error flag.
+
+ * engine.h (_gpgme_engine_get_error): New prototype.
+ * engine.c (_gpgme_engine_get_error): New function.
+ * engine-gpgsm.c (_gpgme_gpgsm_get_error): New function.
+
+ * engine-gpgsm.c (map_assuan_error): New function.
+ (gpgsm_assuan_simple_command): Change return type to GpgmeError,
+ use the new function to map error values.
+ (gpgsm_set_fd): Change return type tp GpgmeError.
+ (_gpgme_gpgsm_op_decrypt): Change type of ERR to GpgmeError.
+ (gpgsm_set_recipients): Likewise. Change type of return value
+ equivalently. Adjust error values.
+ (_gpgme_gpgsm_op_import): Likewise.
+ (_gpgme_gpgsm_op_sign): Likewise.
+ (struct gpgsm_object_s): New member error.
+ (gpgsm_status_handler): Set error if error occurs. Determine
+ error number from ERR line received. If assuan_read_line fails,
+ terminate the connection.
+
+2002-02-01 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (MOSTLYCLEANFILES): New variable.
+
+2002-02-01 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_status_handler): At error, terminate the
+ connection to the server.
+
+2002-01-31 Marcus Brinkmann <[email protected]>
+
+ * rungpg.h: Add STATUS_KEY_CREATED.
+
+ * progress.c: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add progress.c.
+
+ * genkey.c (genkey_status_handler): Use
+ _gpgme_progress_status_handler. Add check for status.
+ (struct genkey_result_s): New structure.
+ (_gpgme_release_genkey_result): New function.
+ (gpgme_op_genkey): Check for error.
+ * gpgme.c (_gpgme_release_result): Call
+ _gpgme_release_genkey_result.
+ * ops.h (_gpgme_release_genkey_result): Add prototype.
+ * types.h (GenKeyResult): New type.
+ * context.h (gpgme_context_s): Add GenKeyResult to member result.
+
+2002-01-30 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (_gpgme_release_result): Call
+ _gpgme_release_delete_result.
+ * ops.h (_gpgme_release_delete_result): Add prototype.
+ * types.h (DeleteResult): New type.
+ * context.h (gpgme_context_s): Add DeleteResult to member result.
+
+ * delete.c (enum delete_problem): New type.
+ (struct delete_result_s): New structure.
+ (_gpgme_release_delete_result): New function.
+ (delete_status_handler): Implement more status codes.
+ (gpgme_op_delete): Return error on failure.
+
+ * import.c (MAX_IMPORTED_FIELDS): Bump up to 14.
+
+2002-01-30 Marcus Brinkmann <[email protected]>
+
+ * import.c (struct import_result_s): New structure.
+ (_gpgme_release_import_result): New function.
+ (append_xml_impinfo): Likewise.
+ (import_status_handler): Implement.
+ * gpgme.c (_gpgme_release_result): Add call to
+ _gpgme_release_import_result.
+ * ops.h (_gpgme_release_import_result): Add prototype.
+ * types.h (ImportResult): New type.
+ * context.h (gpgme_context_s): Add ImportResult to member result.
+
+ * encrypt.c (gpgme_op_encrypt): Code clean up.
+
+2002-01-30 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add lots of comment and fix the formatting. Add
+ gpgme_trustlist_end prototype.
+
+2002-01-29 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h: Add new type GpgmeIdleFunc. Change type of
+ gpgme_register_idle to return and accept this type.
+ * wait.c (gpgme_register_idle): Fix type.
+ Save and return old value of idle_function.
+
+2002-01-29 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist): Implement secret only mode.
+
+ * keylist.c (keylist_colon_handler): Add support for the new "crs"
+ record type.
+
+2002-01-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_release): Call assuan_disconnect,
+ not assuan_pipe_disconnect.
+
+ * Makefile.am (libgpgme_la_LIBADD): Change to link assuan and
+ jnlib (needed by assuan) statically into libgpgme. Linking a
+ static library into a shared library this way is not portable.
+
+2002-01-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (GpgmePassphraseCb): Change type of R_HD from void* to
+ void**.
+
+2002-01-22 Marcus Brinkmann <[email protected]>
+
+ * data.c (gpgme_data_new_from_filepart): Change type of LENGTH
+ from off_t to size_t.
+ * gpgme.h: Likewise.
+
+2002-01-22 Marcus Brinkmann <[email protected]>
+
+ * wait.c (_gpgme_wait_on_condition): If the process finished,
+ reset the pending flag. Also if the operation was cancelled.
+
+ (struct proc_s): Rename READY to DONE.
+ (wait_item_s): Likewise.
+ (set_process_ready): Rename to ...
+ (set_process_done): ... this.
+ (_gpgme_remove_proc_from_wait_queue): Call set_process_done
+ instead set_process_ready.
+ (_gpgme_wait_on_condition): Likewise.
+ (do_select): Rename READY to DONE.
+
+ * verify.c (gpgme_op_verify): Do not set pending to zero here.
+ * sign.c (gpgme_op_sign): Likewise.
+ * import.c (gpgme_op_import): Likewise.
+ * genkey.c (gpgme_op_genkey): Likewise.
+ * export.c (gpgme_op_export): Likewise.
+ * encrypt.c (gpgme_op_encrypt): Likewise.
+ * delete.c (gpgme_op_delete): Likewise.
+ * decrypt-verify.c (gpgme_op_decrypt_verify): Likewise.
+ * decrypt.c (gpgme_op_decrypt): Likewise.
+
+2002-01-22 Marcus Brinkmann <[email protected]>
+
+ * export.c: Cleanup.
+
+2002-01-15 Marcus Brinkmann <[email protected]>
+
+ * trustlist.c: Various source clean ups.
+ (my_isdigit): Removed.
+ (gpgme_op_trustlist_end): New function.
+
+2002-01-13 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c: Various source clean ups, like renaming C to CTX where
+ appropriate.
+ (gpgme_new): Clear R_CTX before starting the work.
+ (my_isdigit): Removed.
+ (my_isxdigit): Likewise.
+
+ * data.c: Various source clean ups.
+ (gpgme_data_new_from_mem): Check BUFFER after clearing R_DH.
+ (gpgme_data_new_with_read_cb): Similar for READ_CB.
+ (gpgme_data_new_from_file): Loop over fread while EINTR.
+ (gpgme_data_new_from_filepart): Rediddled a bit. Allow LENGTH to
+ be zero. Loop over fread while EINTR.
+
+ (my_isdigit): Removed.
+ (my_isxdigit): Likewise.
+
+2001-12-21 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): Replace General_Error with
+ Pipe_Error where appropriate.
+
+2001-12-19 Marcus Brinkmann <[email protected]>
+
+ * engine.c: Include `string.h'. Reported by St�phane Corth�sy.
+
+ * version.c (get_engine_info): Remove prototype.
+
+2001-12-19 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): New variable CHILD_FDS.
+ Fill it with the servers fds, and pass it to assuan_pipe_connect.
+
+2001-12-18 Marcus Brinkmann <[email protected]>
+
+ * keylist.c (gpgme_op_keylist_end): New function.
+ * gpgme.h (gpgme_op_keylist_end): New prototype.
+
+ * engine.h (gpgme_engine_check_version): Move prototype to ...
+ * gpgme.h (gpgme_engine_check_version): ... here.
+
+ * genkey.c (gpgme_op_genkey_start): Remove unused variable.
+
+2001-12-18 Marcus Brinkmann <[email protected]>
+
+ * version.c (gpgme_get_engine_info): Reimplemented.
+ (gpgme_check_engine): Reimplemented.
+ (_gpgme_compare_versions): Return NULL if MY_VERSION is NULL.
+
+ * engine.c: Include `io.h'.
+ (gpgme_engine_get_info): New function.
+ * engine.h (gpgme_engine_check_version, _gpgme_engine_get_info):
+ Add prototype.
+
+2001-12-18 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (struct reap_s, reap_list, reap_list_lock): Moved to ...
+ * engine.c (struct reap_s, reap_list, reap_list_lock): ... here.
+ Include `time.h', `sys/types.h', `assert.h', and `sema.h'.
+
+ * rungpg.c (_gpgme_engine_add_child_to_reap_list): New function.
+ (do_reaping, _gpgme_gpg_housecleaning): Moved to ...
+ * engine.c (do_reaping, _gpgme_engine_housecleaning): ... here.
+ * rungpg.c (_gpgme_gpg_release): Replace code that is now in its
+ own function by call to _gpgme_engine_add_child_to_reap_list().
+
+ * wait.c: Include `engine.h'.
+ (run_idle): Call _gpgme_engine_housecleaning(), not
+ _gpgme_gpg_housecleaning().
+
+2001-12-18 Marcus Brinkmann <[email protected]>
+
+ * key.c (_gpgme_key_append_name): Append, not prepend, the uid.
+ Initialize the next field of the uid structure.
+ (gpgme_key_get_as_xml): Do not list last uid first.
+
+2001-12-17 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_set_colon_line_handler): New
+ function [!ENABLE_GPGSM].
+
+2001-12-14 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_verify): Put TEXT into
+ message_data, not SIG.
+ (_gpgme_gpgsm_op_sign): Use `--detached', not `--detach'.
+
+ * sign.c (sign_status_handler): Call
+ _gpgme_passphrase_status_handler early.
+
+2001-12-14 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c: Revert last change.
+
+2001-12-14 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_status_handler): Freeze the output file
+ handler when ending this operation, otherwise the wait function
+ will sit on it.
+
+2001-12-14 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (struct gpgsm_object_s): New member colon.attic.
+ (_gpgme_gpgsm_new): Initialize some more members.
+ (_gpgme_gpgsm_release): Free the colon line handler's attic line.
+ (gpgsm_status_handler): Rework the inline-data processing.
+
+2001-12-13 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_spawn): Do not add the fds to the child
+ list that are not dup'ed, for those the close-on-exec flag is set
+ now.
+ * version.c (_gpgme_get_program_version): Remove first entry in
+ CFD, as the close-on-exec flag is now set for this fd.
+
+2001-12-13 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_encrypt): Do not add `armor'
+ option to `ENCRYPT'.
+ * engine-gpgsm.c (gpgsm_set_recipients): Free LINE when returning
+ successfully.
+
+2001-12-13 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (close_notify_handler): New function.
+ (_gpgme_gpgsm_new): Manage the file descriptors a
+ bit differently. Do not set close-on-exec flags.
+ (_gpgme_gpgsm_op_decrypt): Do not set message_fd
+ to -1, this is done by the close handler.
+ (_gpgme_gpgsm_op_encrypt): Likewise.
+ (_gpgme_gpgsm_op_import): Likewise (also for output_fd).
+ (_gpgme_gpgsm_op_keylist): Likewise (also for input_fd and output_fd).
+ (_gpgme_gpgsm_op_sign): Likewise.
+ (_gpgme_gpgsm_op_verify): Likewise, but for output_fd.
+
+ * posix-io.c (_gpgme_io_pipe): Set the close-on-exec flag for the
+ non-inherited file descriptor index of the pipe.
+
+2001-12-13 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_set_colon_line_handler): New.
+ (gpgsm_status_handler): Pass datalines to a colon handler
+ * engine.c (_gpgme_engine_set_colon_line_handler): Set the colon
+ handler for gpgsm.
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_keylist): Allow NULL for
+ pattern.
+ (gpgsm_assuan_simple_command): Removed underscore from
+ assuan_write_line.
+ (_gpgme_gpgsm_start): Ditto.
+ (gpgsm_assuan_simple_command): Replaced interal Assuan read
+ function by the new assuan_read_line. Removed the use of the
+ internal header.
+ (gpgsm_status_handler): Ditto. Use the new assuan_pending_line.
+ (_gpgme_gpgsm_start): Use the documented way to get an fd from
+ assuan.
+
+ * keylist.c (keylist_colon_handler): Handle "crt" records
+ * key.h (gpgme_key_s): Add an x509 flag.
+ * key.c (parse_x509_user_id): New.
+ (_gpgme_key_append_name): Handle x.509 names.
+
+2001-12-05 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_status_handler): Make it work with current
+ version of assuan.
+
+2001-12-05 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_set_fd): Accept one more argument OPT.
+ (_gpgme_gpgsm_op_encrypt): Pass armor argument to gpgsm_set_fd for
+ output descriptor.
+ (_gpgme_gpgsm_op_sign): Likewise.
+
+2001-12-05 Marcus Brinkmann <[email protected]>
+
+ * keylist.c (gpgme_op_keylist_next): Set pending to 0 if EOF
+ occurs.
+
+2001-11-26 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Fix stupid typo.
+
+2001-11-24 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (gpgsm_status_handler): Don't break if bsearch fails.
+ Deal with assuan read line returning more than one line (for now).
+
+2001-11-23 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Implement it according to
+ the current protocol definition.
+
+2001-11-23 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_new): Set CLOEXEC flag for parent
+ ends of the pipe.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c: Include stdlib.h and string.h. Also include,
+ for now, rungpg.h and status-table.h.
+ (gpgsm_status_handler): Implement more of the status handler.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * engine.c (_gpgme_engine_op_decrypt): Implement CMS case.
+ (_gpgme_engine_op_delete): Likewise.
+ (_gpgme_engine_op_encrypt): Likewise.
+ (_gpgme_engine_op_export): Likewise.
+ (_gpgme_engine_op_genkey): Likewise.
+ (_gpgme_engine_op_keylist): Likewise.
+ (_gpgme_engine_op_sign): Likewise.
+ (_gpgme_engine_op_trustlist): Likewise.
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_encrypt): New function.
+ (gpgsm_assuan_simple_command): Likewise.
+ (gpgsm_set_recipients): Likewise.
+ (gpgsm_set_fd): Reimplement using gpgsm_assuan_simple_command.
+ (_gpgme_gpgsm_op_delete): New function.
+ (_gpgme_gpgsm_op_export): Likewise.
+ (_gpgme_gpgsm_op_genkey): Likewise.
+ (_gpgme_gpgsm_op_sign): Likewise.
+ (_gpgme_gpgsm_op_keylist): Likewise.
+ (_gpgme_gpgsm_op_trustlist): Likewise.
+ (_gpgme_gpgsm_release): Release command.
+ (_gpgme_gpgsm_op_decrypt): Allocate command.
+ (_gpgme_gpgsm_op_import): Likewise.
+ (gpgsm_status_handler): Also treat `ERR' strings as EOF.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * gpgme.h (gpgme_set_protocol): New prototype.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c (_gpgme_gpgsm_op_decrypt): New function.
+ (_gpgme_gpgsm_op_import): Likewise.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * engine-gpgsm.c: Shuffle around header inclusion a bit, to still
+ keep them seperate.
+ (_gpgme_set_status_handler) [!ENABLE_GPGSM]: New function.
+
+2001-11-22 Werner Koch <[email protected]>
+
+ * engine-gpgsm.c: Include more headers so that NULL and mk_error
+ is defined even with an undefined GPGSM_PATH.
+
+2001-11-22 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (gpg_inbound_handler, write_mem_data, write_cb_data,
+ gpg_outbound_handler): Moved to ...
+ * data.c (_gpgme_data_inbound_handler, write_mem_data,
+ write_cb_data, _gpgme_data_outbound_handler): ... here. Make the
+ _gpgme_* ones non-static.
+ * data.c: Include io.h.
+
+ * ops.h (_gpgme_data_inbound_handler): New prototype.
+ (_gpgme_data_outbound_handler): Likewise.
+ (_gpgme_gpg_spawn): Use these new functions.
+
+ * engine-gpgsm.h (_gpgme_gpgsm_op_decrypt, _gpgme_gpgsm_op_delete,
+ _gpgme_gpgsm_op_encrypt, _gpgme_gpgsm_op_export,
+ _gpgme_gpgsm_op_genkey, _gpgme_gpgsm_op_import,
+ _gpgme_gpgsm_op_keylist, _gpgme_gpgsm_op_sign,
+ _gpgme_gpgsm_op_trustlist, _gpgme_gpgsm_op_verify,
+ _gpgme_gpgsm_start, _gpgme_gpgsm_set_status_handler): New prototype.
+ Include <rungpg.h> for status handler function.
+
+ * engine-gpgsm.c (struct gpgsm_object_s): New members input_fd,
+ input_data, output_fd, output_data, message_fd, message_data, command
+ and status.
+ (_gpgme_gpgsm_new): Open input, output and message pipes before
+ connecting to the client. Close server's ends afterwards.
+ (_gpgme_gpgsm_release): Close open file descriptors. Remove
+ server process from wait queue.
+ (_gpgme_gpgsm_op_verify, _gpgme_gpgsm_start,
+ _gpgme_gpgsm_set_status_handler, gpgms_status_handler): New function.
+
+ * engine.c (_gpgme_engine_start): Implement for GPGME_PROTOCOL_CMS.
+ (_gpgme_engine_set_status_handler): Likewise.
+ (_gpgme_engine_op_verify): Likewise.
+
+2001-11-21 Marcus Brinkmann <[email protected]>
+
+ * context.h: Do not include rungpg.h, but engine.h.
+ (struct gpgme_context_s): Replace member gpg with engine.
+ * gpgme.c (gpgme_release): Release engine, not gpg.
+
+ * recipient.c (_gpgme_append_gpg_args_from_recifgpients): Function
+ moved ...
+ * rungpg.c (_gpgme_append_gpg_args_from_recipients): ... here.
+ Make static, change order of arguments, and return an error value.
+ * ops.h (_gpgme_append_gpg_args_from_recipients): Removed prototype.
+
+ * rungpg.h (_gpgme_gpg_op_verify): Add prototype.
+ (_gpgme_gpg_op_encrypt): Likewise.
+ (_gpgme_gpg_op_decrypt): Likewise.
+ (_gpgme_gpg_op_delete): Likewise.
+ (_gpgme_gpg_op_export): Likewise.
+ (_gpgme_gpg_op_genkey): Likewise.
+ (_gpgme_gpg_op_import): Likewise.
+ (_gpgme_gpg_op_keylist): Likewise.
+ (_gpgme_gpg_op_sign): Likewise.
+ (_gpgme_gpg_op_trustlist): Likewise.
+ * rungpg.c (_gpgme_gpg_op_verify): New function.
+ (_gpgme_gpg_op_encrypt): Likewise.
+ (_gpgme_gpg_op_decrypt): Likewise.
+ (_gpgme_gpg_op_delete): Likewise.
+ (_gpgme_gpg_op_export): Likewise.
+ (_gpgme_gpg_op_genkey): Likewise.
+ (_gpgme_gpg_op_import): Likewise.
+ (_gpgme_gpg_op_keylist): Likewise.
+ (_gpgme_gpg_op_sign): Likewise.
+ (_gpgme_gpg_op_trustlist): Likewise.
+
+ * engine.h (_gpgme_engine_set_status_handler): Add prototype.
+ (_gpgme_engine_set_command_handler): Likewise.
+ (_gpgme_engine_set_colon_line_handler): Likewise.
+ (_gpgme_engine_op_decrypt): Likewise.
+ (_gpgme_engine_op_delete): Likewise.
+ (_gpgme_engine_op_encrypt): Likewise.
+ (_gpgme_engine_op_export): Likewise.
+ (_gpgme_engine_op_genkey): Likewise.
+ (_gpgme_engine_op_import): Likewise.
+ (_gpgme_engine_op_keylist): Likewise.
+ (_gpgme_engine_op_sign): Likewise.
+ (_gpgme_engine_op_trustlist): Likewise.
+ (_gpgme_engine_op_verify): Likewise.
+ (_gpgme_engine_start): Likewise.
+ * engine.c (_gpgme_engine_set_status_handler): New function.
+ (_gpgme_engine_set_command_handler): Likewise.
+ (_gpgme_engine_set_colon_line_handler): Likewise.
+ (_gpgme_engine_op_decrypt): Likewise.
+ (_gpgme_engine_op_delete): Likewise.
+ (_gpgme_engine_op_encrypt): Likewise.
+ (_gpgme_engine_op_export): Likewise.
+ (_gpgme_engine_op_genkey): Likewise.
+ (_gpgme_engine_op_import): Likewise.
+ (_gpgme_engine_op_keylist): Likewise.
+ (_gpgme_engine_op_sign): Likewise.
+ (_gpgme_engine_op_trustlist): Likewise.
+ (_gpgme_engine_op_verify): Likewise.
+ (_gpgme_engine_start): Likewise.
+
+ * verify.c (gpgme_op_verify_start): Reimplement in terms of above
+ functions.
+ * encrypt.c (gpgme_op_encrypt_start): Likewise.
+ * decrypt.c (_gpgme_decrypt_start): Likewise.
+ * passphrase.c (_gpgme_passphrase_start): Likewise.
+ * keylist.c (gpgme_op_keylist_start): Likewise.
+
+2001-11-20 Marcus Brinkmann <[email protected]>
+
+ * types.h: Add types EngineObject and GpgsmObject.
+
+ * Makefile.am (libgpgme_la_SOURCES): Add engine-gpgsm.h,
+ engine-gpgsm.c, engine.h and engine.c.
+ * engine.h: New file.
+ * engine.c: Likewise.
+ * engine-gpgsm.h: Likewise.
+ * engine-gpgsm.c: Likewise.
+
+ * rungpg.c (_gpgme_gpg_get_version): New function.
+ (_gpgme_gpg_check_version): Likewise.
+ * rungpg.h: Add prototypes for _gpgme_gpg_get_version and
+ _gpgme_gpg_check_version.
+
+ * version.c (compare_versions): Rename to ...
+ (_gpgme_compare_versions): ... this. Make non-static.
+ (gpgme_check_version): Use _gpgme_compare_versions rather than
+ compare_versions.
+ (gpgme_check_engine): Likewise.
+ * ops.h (_gpgme_get_program_version): Add prototype.
+
+2001-11-20 Marcus Brinkmann <[email protected]>
+
+ * Makefile.am (libgpgme_la_INCLUDES): Remove obsolete directive.
+ (AM_CPPFLAGS): New directive [BUILD_ASSUAN].
+ (libgpgme_la_LIBADD): Likewise.
+
+2001-11-20 Marcus Brinkmann <[email protected]>
+
+ * version.c: Remove global variables lineno and
+ tmp_engine_version.
+ (version_handler): Removed.
+ (_gpgme_get_program_version): New function.
+ (get_engine_info): Don't use context and version_handler,
+ but _gpgme_get_program_version.
+ * ops.h (_gpgme_get_program_version): Add prototype for
+ _gpgme_get_program_version (we expect to use it elsewhere soon).
+
+2001-11-18 Marcus Brinkmann <[email protected]>
+
+ * version.c (get_engine_info): If GnuPG is not available, return
+ an error message.
+ * posix-util.c (_gpgme_get_gpg_path): Allow GPG_PATH to be
+ undefined.
+ (_gpgme_get_gpgsm_path): New function.
+ * w32-util.c (find_program_in_registry): New static function.
+ (_gpgme_get_gpg_path): Allow GPG_PATH to be undefined. Rework
+ to use find_program_in_registry.
+ (_gpgme_get_gpgsm_path): New function.
+ (util.h): Prototype _gpgme_get_gpgsm_path).
+ * rungpg.c (_gpgme_gpg_spawn): Verify that _gpgme_get_gpg_path()
+ returns non-null.
+
+2001-11-16 Marcus Brinkmann <[email protected]>
+
+ * decrypt-verify.c: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add decrypt-verify.c.
+ * types.h: Add decrypt-verify types.
+ * ops.h: Likewise.
+ * context.h: Add result type for decrypt-verify.
+ * gpgme.h: Add decrypt-verify prototypes.
+
+ * decrypt.c (decrypt_status_handler): Renamed to ...
+ (_gpgme_decrypt_status_handler): ... this. Make non-static.
+ (_gpgme_decrypt_start): New function, derived from
+ gpgme_op_decrypt_start.
+ (gpgme_op_decrypt_start): Reimplement in terms of
+ _gpgme_decrypt_start.
+ (_gpgme_decrypt_result): New function to retrieve error value.
+ (gpgme_op_decrypt): Use _gpgme_decrypt_result.
+ * ops.h: Add prototypes for new functions.
+
+ * verify.c (verify_status_handler): Renamed to ...
+ (_gpgme_verify_status_handler): ... this. Make non-static.
+ (gpgme_op_verify_start): Use new function name.
+ (intersect_stati): Renamed to ...
+ (_gpgme_intersect_stati): ... this. Make non-static.
+ (gpgme_op_verify): Use new name.
+ * ops.h: Add prototypes for new functions.
+
+2001-11-16 Marcus Brinkmann <[email protected]>
+
+ * passphrase.c: New file.
+ * Makefile.am (libgpgme_la_SOURCES): Add passphrase.c.
+ * ops.h (_gpgme_passphrase_result): Add prototypes from
+ passphrase.c.
+ * types.h: Likewise.
+ * context.h: Add member passphrase to result.
+ * gpgme.c (_gpgme_release_result): Release passphrase member.
+
+ * decrypt.c: Some formatting and variable name changes (like
+ CTX instead C).
+ (struct decrypt_result_s): Remove members now found in
+ passphrase result.
+ (_gpgme_release_decrypt_result): Don't release removed members.
+ (decrypt_status_handler): Call _gpgme_passphrase_status_handler,
+ and don't handle the cases catched there.
+ (command_handler): Removed.
+ (gpgme_op_decrypt_start): Don't set command handler, but invoke
+ _gpgme_passphrase_start which does it.
+ (gpgme_op_decrypt): Invoke _gpgme_passphrase_result and drop the
+ cases covered by it.
+
+ * sign.c Some formatting and variable name changes (like
+ CTX instead C).
+ (struct sign_result_s): Remove members now found in
+ passphrase result.
+ (_gpgme_release_sign_result): Don't release removed members.
+ (sign_status_handler): Call _gpgme_passphrase_status_handler,
+ and don't handle the cases catched there.
+ (command_handler): Removed.
+ (gpgme_op_sign_start): Don't set command handler, but invoke
+ _gpgme_passphrase_start which does it.
+ (gpgme_op_sign): Invoke _gpgme_passphrase_result and drop the
+ cases covered by it.
+
+2001-11-15 Marcus Brinkmann <[email protected]>
+
+ * decrypt.c (command_handler): Fix last change.
+
+2001-11-15 Marcus Brinkmann <[email protected]>
+
+ * verify.c (_gpgme_release_verify_result): Rename RES to RESULT.
+ Rename R2 to NEXT_RESULT.
+ (intersect_stati): Rename RES to RESULT.
+ (gpgme_get_sig_status): Likewise. Do not check return_type, but
+ the member verify of result.
+ (gpgme_get_sig_key): Likewise.
+
+ * sign.c (_gpgme_release_sign_result): Rename RES to RESULT. If
+ RESULT is zero, return.
+ (sign_status_handler, command_handler): Do not check return_type,
+ but the member sign of result.
+ (gpgme_op_sign): Likewise. Drop assertion.
+
+ * encrypt.c (_gpgme_release_encrypt_result): Rename RES to RESULT.
+ If RESULT is zero, return.
+ (encrypt_status_handler): Do not check return_type, but the member
+ encrypt of result.
+ (gpgme_op_encrypt): Likewise. Drop assertion.
+
+ * decrypt.c (_gpgme_release_decrypt_result): Rename RES to RESULT.
+ (create_result_struct): Do not set result_type.
+ (command_handler, decrypt_status_handler): Do not check
+ return_type, but the member decrypt of result.
+ (gpgme_op_decrypt): Likewise. Drop assertion.
+
+ * context.h (enum ResultType): Removed.
+ (struct gpgme_context_s): Remove member result_type.
+ (struct result): Replaces union result.
+ * gpgme.c: Include string.h.
+ (_gpgme_release_result): Release all members of c->result, which
+ is now a struct. Zero out all members of the struct afterwards.
+
+2001-11-11 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (_gpgme_gpg_release): Release GPG->cmd.cb_data.
+ Release all members of the list GPG->arglist.
+ Reported by Michael Schmidt <[email protected]>.
+
+2001-11-02 Marcus Brinkmann <[email protected]>
+
+ * rungpg.c (pipemode_copy): Change type of NBYTES to size_t.
+
+ * key.c: Include string.h.
+ * data.c: Likewise.
+ * recipient.c: Likewise.
+
+2001-10-29 Marcus Brinkmann <[email protected]>
+
+ * context.h: New member signers_len.
+ * signers.c (gpgme_signers_clear): Require that signers are
+ non-NULL with assertion. Use signers_len to determine how much
+ keys to release. Add documentation.
+ (gpgme_signers_add): Use signers_len to determine if the buffer is
+ large enough. Use xtryrealloc rather than xtrymalloc and copying.
+ Add documentation.
+ (gpgme_signers_enum): Use signers_len to determine if key is
+ available. Add documentation.
+
+2001-10-22 Marcus Brinkmann <[email protected]>
+
+ * data.c (_gpgme_data_append): Check if LENGTH is smaller than
+ ALLOC_CHUNK, not DH->length.
+
+2001-10-17 Marcus Brinkmann <[email protected]>
+
+ * gpgme.c (gpgme_set_protocol): Fix last change.
+
+2001-10-15 Werner Koch <[email protected]>
+
+ * gpgme.h (GpgmeProtocol): New.
+ * gpgme.c (gpgme_set_protocol): New.
+
+2001-09-26 Werner Koch <[email protected]>
+
+ * gpgme.c (gpgme_set_passphrase_cb): Ignore a NULL context.
+ (gpgme_set_progress_cb): Ditto. Suggested by Mark Mutz.
+
+2001-09-17 Werner Koch <[email protected]>
+
+ * keylist.c (finish_key): Shortcut for no tmp_key. Changed all
+ callers to use this function without a check for tmp_key.
+
+ * keylist.c (gpgme_op_keylist_next): Reset the key_cond after
+ emptying the queue. Bug reported by St�phane Corth�sy.
+
+2001-09-12 Werner Koch <[email protected]>
+
+ * data.c (gpgme_data_rewind): Allow rewind for callbacks.
+
+2001-09-07 Werner Koch <[email protected]>
+
+ * rungpg.h: Add NO_RECP.
+ * encrypt.c (encrypt_status_handler): Take on No_RECP.
+ (gpgme_op_encrypt): Better error return.
+
+ * verify.c (verify_status_handler): Take on NODATA.
+
+2001-09-03 Werner Koch <[email protected]>
+
+ * rungpg.h: Added STATUS_INV_RECP.
+ * gpgme.c (_gpgme_release_result): Add support for new
+ EncryptResult object.
+ * encrypt.c (append_xml_encinfo): New.
+ (encrypt_status_handler): Add some status parsing.
+ (_gpgme_release_encrypt_result): New.
+
+2001-08-29 Werner Koch <[email protected]>
+
+ * recipient.c (gpgme_recipients_release): Free the list. By Timo.
+
+ * keylist.c (keylist_colon_handler): Do a finish key if we receive
+ an EOF here. This is probably the reason for a lot of bugs
+ related to keylisting. It is so obvious. Kudos to Enno Cramer
+ for pointing that out.
+
+2001-08-28 Werner Koch <[email protected]>
+
+ * gpgme.c, gpgme.h (gpgme_get_op_info): New.
+ (_gpgme_set_op_info): New.
+ (_gpgme_release_result): Reset the op_info here.
+ * sign.c (append_xml_siginfo): New.
+ (sign_status_handler): Store the sig create information.
+
+2001-07-31 Werner Koch <[email protected]>
+
+ * encrypt.c (gpgme_op_encrypt): Hack to detect no valid recipients.
+
+2001-07-30 Werner Koch <[email protected]>
+
+ * gpgme.c (gpgme_get_armor,gpgme_get_textmode): New.
+
+ * rungpg.c (build_argv): Disable armor comments
+ * w32-io.c (build_commandline): Need to add quotes here
+
+2001-07-24 Werner Koch <[email protected]>
+
+ * data.c (gpgme_data_read): Add a a way to return the available bytes.
+
+2001-07-23 Werner Koch <[email protected]>
+
+ * util.c: Removed stpcpy() because we use the version from jnlib.
+
+2001-07-19 Werner Koch <[email protected]>
+
+ * mkstatus: Define the collating sequence for sort.
+
+2001-06-26 Werner Koch <[email protected]>
+
+ * rungpg.h: Add STATUS_UNEXPECTED as suggested by Timo.
+
+2001-06-15 Werner Koch <[email protected]>
+
+ * keylist.c (set_userid_flags): Fixed the assigned values. Kudos
+ to Timo for pointing this out.
+
+2001-06-01 Werner Koch <[email protected]>
+
+ * debug.c (_gpgme_debug_begin): Fixed a /tmp race. Noted by
+ Johannes Poehlmann.
+
+2001-05-28 Werner Koch <[email protected]>
+
+ * version.c (gpgme_check_engine): Stop version number parsing at
+ the opening angle and not the closing one. By Tommy Reynolds.
+
+2001-05-01 Jos� Carlos Garc�a Sogo <[email protected]>
+
+ * encrypt.c (gpgme_op_encrypt_start): Deleted the assert ( !c->gpg )
+ line, because it gave an error if another operation had been made
+ before using the same context.
+
+ * decrypt.c (gpgme_op_decrypt_start): The same as above. Also added
+ one line to release the gpg object in the context (if any).
+
+2001-04-26 Werner Koch <[email protected]>
+
+ * key.c, key.h (_gpgme_key_cache_init): New.
+ (_gpgme_key_cache_add): New.
+ (_gpgme_key_cache_get): New.
+ * version.c (do_subsystem_inits): Init the cache.
+ * keylist.c (finish_key): Put key into the cache
+ * verify.c (gpgme_get_sig_key): First look into the cache.
+
+2001-04-19 Werner Koch <[email protected]>
+
+ * keylist.c (parse_timestamp): Adjusted for the changed
+ --fixed-list-mode of gpg 1.0.4h.
+
+2001-04-05 Werner Koch <[email protected]>
+
+ * verify.c (gpgme_op_verify_start): Enabled pipemode for detached sigs.
+
+2001-04-04 Werner Koch <[email protected]>
+
+ * w32-io.c (_gpgme_io_select): Don't select on the writer if there
+ are still bytes pending. Timo found this not easy to track down
+ race condition.
+
+2001-04-02 Werner Koch <[email protected]>
+
+ * gpgme.h: Add GPGME_ATTR_KEY_{EXPIRED,DISABLED}.
+ * key.c (gpgme_key_get_ulong_attr): And return those attribs.
+
+ * verify.c (gpgme_get_sig_key): Set keyliosting mode depending on
+ the mode set in the current context. Suggested by Timo.
+
+ * key.c (gpgme_key_get_ulong_attr): Return can_certify and not
+ can_encrypt. By Timo.
+
+2001-03-30 Werner Koch <[email protected]>
+
+ * debug.c (debug_init): Allow to specify a debug file.
+ (_gpgme_debug_level): New.
+
+ * posix-io.c (_gpgme_io_read, _gpgme_io_write): Print output.
+ (_gpgme_io_select): Debug only with level > 2.
+
+2001-03-15 Werner Koch <[email protected]>
+
+ * rungpg.c: Included time.h.
+
+ * key.h: New keyflags for capabilities.
+ * keylist.c (set_mainkey_capability, set_subkey_capability): New.
+ (keylist_colon_handler): Parse them.
+ * gpgme.h: New attribute values for capabilties.
+ * key.c (gpgme_key_get_string_attr): Return them.
+ (capabilities_to_string): New.
+ (gpgme_key_get_ulong_attr): Return the global caps.
+
+2001-03-14 Werner Koch <[email protected]>
+
+ * w32-io.c (destroy_reader,destroy_writer): Fixed syntax error.
+ Thanks to Jan Oliver Wagner.
+
+2001-03-13 Werner Koch <[email protected]>
+
+ * context.h: Add invalid and revoke flags to user_id structure.
+ * keylist.c (gpgme_op_keylist_start): Use --fixed-list-mode.
+ (keylist_colon_handler): Adjust for that.
+ (set_userid_flags): New.
+ (set_mainkey_trust_info): Handle new key invalid flag
+ (set_subkey_trust_info): Ditto.
+ * gpgme.h: Add new attributes for key and user ID flags.
+ * key.c (_gpgme_key_append_name): Init these flags
+ (gpgme_key_get_as_xml): Print them.
+ (one_uid_as_xml): New helper for above.
+ (gpgme_key_get_string_attr, gpgme_key_get_ulong_attr):
+ Return the new attributes. Enhanced, so that subkey information
+ can be returned now.
+
+2001-02-28 Werner Koch <[email protected]>
+
+ * w32-io.c (destroy_reader): Set stop_me flag.
+ (writer,create_writer,destroy_writer,find_writer,kill_writer): New.
+ (_gpgme_io_write): Use a writer thread to avaoid blocking.
+ (_gpgme_io_close): Cleanup a writer thread
+ (_gpgme_io_select): Repalce tthe faked wait on writing by a real
+ waiting which is now possible due to the use of a writer thread.
+
+2001-02-20 Werner Koch <[email protected]>
+
+ * w32-io.c (destroy_reader,kill_reader): New.
+ (create_reader, reader): Add a new event to stop the thread.
+ (_gpgme_io_close): Kill the reader thread.
+
+ * posix-io.c (_gpgme_io_select): Handle frozen fds here.
+ * 32-io.c (_gpgme_io_select): Ditto. Removed a bunch of unused code.
+
+ * wait.c: Reworked the whole thing.
+ * rungpg.c (_gpgme_gpg_new): Init pid to -1.
+ (_gpgme_gpg_release): Remove the process from the wait queue.
+
+2001-02-19 Werner Koch <[email protected]>
+
+ * w32-io.c (_gpgme_io_set_close_notify): New.
+ (_gpgme_io_close): Do the notification.
+
+ * posix-io.c (_gpgme_io_select): Use a 1 sec timeout and not 200
+ microseconds.
+
+ * wait.c (remove_process): Don't close the fd here.
+ (do_select): Set the fd to -1 and remove the is_closed flag everywhere.
+ (_gpgme_wait_on_condition): Remove the assert on the queue and
+ break out if we could not find the queue. The whole thing should
+ be reworked.
+
+ * posix-io.c (_gpgme_io_set_close_notify): New.
+ (_gpgme_io_close): Do the notification.
+
+ * rungpg.c (close_notify_handler): New.
+ (_gpgme_gpg_new): Register a callback for the fd.
+ (_gpgme_gpg_set_colon_line_handler): Ditto.
+ (build_argv): Ditto
+
+2001-02-13 Werner Koch <[email protected]>
+
+ * rungpg.c (struct reap_s): Replaced pid_t by int.
+
+ * types.h: Add ulong typedef.
+
+ * rungpg.c (do_reaping,_gpgme_gpg_housecleaning): New.
+ (_gpgme_gpg_release): Reap children.
+ * io.h, posix-io.c (_gpgme_io_kill): New.
+ * w32-io.c (_gpgme_io_kill): New (dummy).
+
+ * keylist.c (gpgme_op_keylist_start): Cancel a pending request.
+
+ * posix-io.c (_gpgme_io_read): Add some debug output.
+ (_gpgme_io_write): Ditto.
+ (_gpgme_io_select): Increased the timeout.
+
+2001-02-12 Werner Koch <[email protected]>
+
+ Enhanced the signature verification, so that it can how handle
+ more than one signature and is able to return more information on
+ the signatures.
+ * verify.c (gpgme_get_sig_key): New.
+ (gpgme_get_sig_status): New.
+
+ * gpgme.h: Add stdio.h.
+ (GpgmeSigStat): New status DIFF.
+
+2001-02-01 Werner Koch <[email protected]>
+
+ * w32-io.c (set_synchronize): Add EVENT_MODIFY_STATE. Add Debug
+ code to all Set/ResetEvent().
+
+ * rungpg.c (read_status): Check for end of stream only if we have
+ an r. By Timo.
+
+2001-01-31 Werner Koch <[email protected]>
+
+ * wait.c (_gpgme_wait_on_condition): Removed all exit code processing.
+ (propagate_term_results,clear_active_fds): Removed.
+ (count_active_fds): Renamed to ..
+ (count_active_and_thawed_fds): .. this and count only thawed fds.
+
+ * rungpg.c (gpg_colon_line_handler): Return colon.eof and not
+ status.eof ;-)
+
+2001-01-30 Werner Koch <[email protected]>
+
+ * w32-io.c (_gpgme_io_spawn): Use the supplied path arg.
+
+ * version.c (get_engine_info): Return better error information.
+
+ * posix-util.c, w32-util.c: New.
+ (_gpgme_get_gpg_path): New, suggested by Jan-Oliver.
+ * rungpg.c (_gpgme_gpg_spawn): Use new function to get GPG's path.
+
+ * signers.c (gpgme_signers_add): Ooops, one should test code and
+ not just write it; the newarr was not assigned. Thanks to Jos�
+ for pointing this out. Hmmm, still not tested, why shoudl a coder
+ test his fix :-)
+
+ * w32-io.c: Does now use reader threads, so that we can use
+ WaitForMultipleObjects.
+ * sema.h, posix-sema.c, w32-sema.c: Support for Critcial sections.
+ Does currently only work for W32.
+
+ * debug.c, util.h : New. Changed all fprintfs to use this new
+ set of debugging functions.
+
+2001-01-23 Werner Koch <[email protected]>
+
+ * data.c (_gpgme_data_release_and_return_string): Fixed string
+ termination.
+
+2001-01-22 Werner Koch <[email protected]>
+
+ * delete.c: New.
+
+ * signers.c: New.
+ * key.c (gpgme_key_ref, gpgme_key_unref): New.
+ * sign.c (gpgme_op_sign_start): Allow the use of other keys.
+
+ * version.c (gpgme_get_engine_info,gpgme_check_engine): New.
+ * rungpg.c (_gpgme_gpg_set_simple_line_handler): New.
+
+2001-01-05 Werner Koch <[email protected]>
+
+ * data.c (gpgme_data_rewind): Allow to rewind data_type_none.
+
+
+ Copyright 2001, 2002, 2003, 2004 g10 Code GmbH
+
+ This file is free software; as a special exception the author gives
+ unlimited permission to copy and/or distribute it, with or without
+ modifications, as long as this notice is preserved.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/branches/gpgme-1-0-branch/gpgme/Makefile.am b/branches/gpgme-1-0-branch/gpgme/Makefile.am
new file mode 100644
index 00000000..00f8c4db
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/Makefile.am
@@ -0,0 +1,126 @@
+# 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 this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = gpgme-config.in gpgme.m4 mkstatus libgpgme.vers
+BUILT_SOURCES = status-table.h
+MOSTLYCLEANFILES = status-table.h
+bin_SCRIPTS = gpgme-config
+m4datadir = $(datadir)/aclocal
+m4data_DATA = gpgme.m4
+include_HEADERS = gpgme.h
+
+if HAVE_PTHREAD
+ltlib_gpgme_pthread = libgpgme-pthread.la
+else
+ltlib_gpgme_pthread =
+endif
+if HAVE_PTH
+ltlib_gpgme_pth = libgpgme-pth.la
+else
+ltlib_gpgme_pth =
+endif
+
+noinst_LTLIBRARIES = libgpgme-real.la
+lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_pthread) $(ltlib_gpgme_pth)
+
+if HAVE_LD_VERSION_SCRIPT
+libgpgme_version_script_cmd = -Wl,--version-script=$(srcdir)/libgpgme.vers
+else
+libgpgme_version_script_cmd =
+endif
+
+if BUILD_ASSUAN
+assuan_cppflags = -I$(top_srcdir)/assuan
+assuan_libobjs = ../assuan/libassuan.la
+else
+assuan_cppflags =
+assuan_libobjs =
+endif
+
+if HAVE_DOSISH_SYSTEM
+system_components = w32-util.c w32-sema.c w32-io.c
+else
+system_components = ath.h posix-util.c posix-sema.c posix-io.c
+endif
+
+if HAVE_GPGSM
+gpgsm_components = engine-gpgsm.c
+else
+gpgsm_components =
+endif
+
+libgpgme_real_la_SOURCES = \
+ gpgme.h util.h conversion.c get-env.c context.h ops.h \
+ data.h data.c data-fd.c data-stream.c data-mem.c data-user.c \
+ data-compat.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.c keylist.c trust-item.c trustlist.c \
+ import.c export.c genkey.c delete.c edit.c \
+ engine.h engine-backend.h engine.c rungpg.c status-table.h \
+ $(gpgsm_components) sema.h io.h $(system_components) \
+ debug.c debug.h gpgme.c version.c error.c
+
+# libgpgme_la_SOURCES = ath.h ath.c
+if HAVE_PTH
+ ath_pth_src = ath-pth-compat.c
+else
+ ath_pth_src =
+endif
+if HAVE_PTHREAD
+ ath_pthread_src = ath-pthread-compat.c
+else
+ ath_pthread_src =
+endif
+libgpgme_la_SOURCES = ath.h ath-compat.c $(ath_pth_src) $(ath_pthread_src)
+libgpgme_pthread_la_SOURCES = ath.h ath-pthread.c
+libgpgme_pth_la_SOURCES = ath.h ath-pth.c
+
+AM_CPPFLAGS = $(assuan_cppflags) @GPG_ERROR_CFLAGS@
+
+libgpgme_la_LDFLAGS = $(libgpgme_version_script_cmd) -version-info \
+ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
+libgpgme_la_DEPENDENCIES = libgpgme-real.la $(assuan_libobjs) \
+ @LTLIBOBJS@ $(srcdir)/libgpgme.vers
+libgpgme_la_LIBADD = libgpgme-real.la $(assuan_libobjs) @LTLIBOBJS@ \
+ @GPG_ERROR_LIBS@
+
+libgpgme_pthread_la_LDFLAGS = $(libgpgme_version_script_cmd) -version-info \
+ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
+libgpgme_pthread_la_DEPENDENCIES = libgpgme-real.la $(assuan_libobjs) \
+ @LTLIBOBJS@ $(srcdir)/libgpgme.vers
+libgpgme_pthread_la_LIBADD = libgpgme-real.la $(assuan_libobjs) @LTLIBOBJS@ \
+ -lpthread @GPG_ERROR_LIBS@
+
+libgpgme_pth_la_CPPFLAGS = $(AM_CPPFLAGS) @PTH_CPPFLAGS@
+libgpgme_pth_la_LDFLAGS = @PTH_LDFLAGS@ \
+ $(libgpgme_version_script_cmd) -version-info \
+ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@
+libgpgme_pth_la_DEPENDENCIES = libgpgme-real.la $(assuan_libobjs) \
+ @LTLIBOBJS@ $(srcdir)/libgpgme.vers
+libgpgme_pth_la_LIBADD = libgpgme-real.la $(assuan_libobjs) @LTLIBOBJS@ \
+ @PTH_LIBS@ @GPG_ERROR_LIBS@
+
+status-table.h : gpgme.h
+ $(srcdir)/mkstatus < $(srcdir)/gpgme.h > status-table.h
diff --git a/branches/gpgme-1-0-branch/gpgme/ath-compat.c b/branches/gpgme-1-0-branch/gpgme/ath-compat.c
new file mode 100644
index 00000000..a4bd3f16
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath-compat.c
@@ -0,0 +1,185 @@
+/* ath.c - self-adapting thread-safeness library
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+#endif
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/wait.h>
+#endif
+
+#include "ath.h"
+
+static struct ath_ops *ath_ops;
+
+void
+ath_init (void)
+{
+ if (0)
+ ;
+#ifdef HAVE_PTHREAD
+ else if (!ath_ops)
+ ath_ops = ath_pthread_available ();
+#endif
+#ifdef HAVE_PTH
+ else if (!ath_ops)
+ ath_ops = ath_pth_available ();
+#endif
+}
+
+
+int
+ath_mutex_init (ath_mutex_t *lock)
+{
+ if (!ath_ops)
+ return 0;
+
+ return ath_ops->mutex_init (lock, 0);
+}
+
+
+int
+ath_mutex_destroy (ath_mutex_t *lock)
+{
+ int err;
+ if (!ath_ops)
+ return 0;
+ err = ath_ops->mutex_init (lock, 1);
+ if (!err)
+ err = ath_ops->mutex_destroy (*lock);
+ return err;
+}
+
+
+int
+ath_mutex_lock (ath_mutex_t *lock)
+{
+ int err;
+
+ if (!ath_ops)
+ return 0;
+ err = ath_ops->mutex_init (lock, 1);
+ if (!err)
+ err = ath_ops->mutex_lock (*lock);
+ return err;
+}
+
+
+int
+ath_mutex_unlock (ath_mutex_t *lock)
+{
+ int err;
+
+ if (!ath_ops)
+ return 0;
+ err = ath_ops->mutex_init (lock, 1);
+ if (!err)
+ err = ath_ops->mutex_unlock (*lock);
+ return err;
+}
+
+
+ssize_t
+ath_read (int fd, void *buf, size_t nbytes)
+{
+ if (ath_ops && ath_ops->read)
+ return ath_ops->read (fd, buf, nbytes);
+ else
+ return read (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_write (int fd, const void *buf, size_t nbytes)
+{
+ if (ath_ops && ath_ops->write)
+ return ath_ops->write (fd, buf, nbytes);
+ else
+ return write (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout)
+{
+ if (ath_ops && ath_ops->select)
+ return ath_ops->select (nfd, rset, wset, eset, timeout);
+ else
+ return select (nfd, rset, wset, eset, timeout);
+}
+
+
+ssize_t
+ath_waitpid (pid_t pid, int *status, int options)
+{
+ if (ath_ops && ath_ops->waitpid)
+ return ath_ops->waitpid (pid, status, options);
+ else
+ return waitpid (pid, status, options);
+}
+
+
+int
+ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
+{
+ if (ath_ops && ath_ops->accept)
+ return ath_ops->accept (s, addr, length_ptr);
+ else
+ return accept (s, addr, length_ptr);
+}
+
+
+int
+ath_connect (int s, const struct sockaddr *addr, socklen_t length)
+{
+ if (ath_ops && ath_ops->connect)
+ return ath_ops->connect (s, addr, length);
+ else
+ return connect (s, addr, length);
+}
+
+
+int
+ath_sendmsg (int s, const struct msghdr *msg, int flags)
+{
+ if (ath_ops && ath_ops->sendmsg)
+ return ath_ops->sendmsg (s, msg, flags);
+ else
+ return sendmsg (s, msg, flags);
+}
+
+
+int
+ath_recvmsg (int s, struct msghdr *msg, int flags)
+{
+ if (ath_ops && ath_ops->recvmsg)
+ return ath_ops->recvmsg (s, msg, flags);
+ else
+ return recvmsg (s, msg, flags);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ath-pth-compat.c b/branches/gpgme-1-0-branch/gpgme/ath-pth-compat.c
new file mode 100644
index 00000000..75b6fb4f
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath-pth-compat.c
@@ -0,0 +1,123 @@
+/* ath-pth.c - Pth module for self-adapting thread-safeness library
+ * Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pth.h>
+
+#include "ath.h"
+
+#pragma weak pth_mutex_init
+#pragma weak pth_mutex_acquire
+#pragma weak pth_mutex_release
+#pragma weak pth_read
+#pragma weak pth_write
+#pragma weak pth_select
+#pragma weak pth_waitpid
+#pragma weak pth_accept
+#pragma weak pth_connect
+
+/* The lock we take while checking for lazy lock initialization. */
+static pth_mutex_t check_init_lock = PTH_MUTEX_INIT;
+
+/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if
+ it is not already initialized. */
+static int
+mutex_pth_init (void **priv, int just_check)
+{
+ int err = 0;
+
+ if (just_check)
+ pth_mutex_acquire (&check_init_lock, 0, NULL);
+ if (!*priv || !just_check)
+ {
+ pth_mutex_t *lock = malloc (sizeof (pth_mutex_t));
+ if (!lock)
+ err = ENOMEM;
+ if (!err)
+ {
+ err = pth_mutex_init (lock);
+ if (err == FALSE)
+ err = errno;
+ else
+ err = 0;
+
+ if (err)
+ free (lock);
+ else
+ *priv = lock;
+ }
+ }
+ if (just_check)
+ pth_mutex_release (&check_init_lock);
+ return err;
+}
+
+
+static int
+mutex_pth_destroy (void *priv)
+{
+ free (priv);
+ return 0;
+}
+
+
+static int
+mutex_pth_lock (void *priv)
+{
+ int ret = pth_mutex_acquire ((pth_mutex_t *) priv, 0, NULL);
+ return ret == FALSE ? errno : 0;
+}
+
+
+static int
+mutex_pth_unlock (void *priv)
+{
+ int ret = pth_mutex_release ((pth_mutex_t *) priv);
+ return ret == FALSE ? errno : 0;
+}
+
+
+static struct ath_ops ath_pth_ops =
+ {
+ mutex_pth_init,
+ mutex_pth_destroy,
+ mutex_pth_lock,
+ mutex_pth_unlock,
+ pth_read,
+ pth_write,
+ pth_select,
+ pth_waitpid,
+ pth_accept,
+ pth_connect,
+ NULL, /* FIXME: When GNU PTh has sendmsg. */
+ NULL /* FIXME: When GNU PTh has recvmsg. */
+ };
+
+
+struct ath_ops *
+ath_pth_available (void)
+{
+ if (pth_mutex_init && pth_mutex_acquire && pth_mutex_release
+ && pth_read && pth_write && pth_select && pth_waitpid)
+ return &ath_pth_ops;
+ else
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ath-pth.c b/branches/gpgme-1-0-branch/gpgme/ath-pth.c
new file mode 100644
index 00000000..2c7cd5aa
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath-pth.c
@@ -0,0 +1,177 @@
+/* ath-pth.c - Pth module for self-adapting thread-safeness library
+ 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. */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include <pth.h>
+
+#include "ath.h"
+
+
+/* The lock we take while checking for lazy lock initialization. */
+static pth_mutex_t check_init_lock = PTH_MUTEX_INIT;
+
+/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if
+ it is not already initialized. */
+static int
+mutex_pth_init (ath_mutex_t *priv, int just_check)
+{
+ int err = 0;
+
+ if (just_check)
+ pth_mutex_acquire (&check_init_lock, 0, NULL);
+ if (!*priv || !just_check)
+ {
+ pth_mutex_t *lock = malloc (sizeof (pth_mutex_t));
+ if (!lock)
+ err = ENOMEM;
+ if (!err)
+ {
+ err = pth_mutex_init (lock);
+ if (err == FALSE)
+ err = errno;
+ else
+ err = 0;
+
+ if (err)
+ free (lock);
+ else
+ *priv = (ath_mutex_t) lock;
+ }
+ }
+ if (just_check)
+ pth_mutex_release (&check_init_lock);
+ return err;
+}
+
+
+void
+ath_init (void)
+{
+ /* Nothing to do. */
+}
+
+
+int
+ath_mutex_init (ath_mutex_t *lock)
+{
+ return mutex_pth_init (lock, 0);
+}
+
+
+int
+ath_mutex_destroy (ath_mutex_t *lock)
+{
+ int err = mutex_pth_init (lock, 1);
+ if (!err)
+ {
+ /* GNU Pth has no destructor function. */
+ free (*lock);
+ }
+ return err;
+}
+
+
+int
+ath_mutex_lock (ath_mutex_t *lock)
+{
+ int ret = mutex_pth_init (lock, 1);
+ if (ret)
+ return ret;
+
+ ret = pth_mutex_acquire ((pth_mutex_t *) *lock, 0, NULL);
+ return ret == FALSE ? errno : 0;
+}
+
+
+int
+ath_mutex_unlock (ath_mutex_t *lock)
+{
+ int ret = mutex_pth_init (lock, 1);
+ if (ret)
+ return ret;
+
+ ret = pth_mutex_release ((pth_mutex_t *) *lock);
+ return ret == FALSE ? errno : 0;
+}
+
+
+ssize_t
+ath_read (int fd, void *buf, size_t nbytes)
+{
+ return pth_read (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_write (int fd, const void *buf, size_t nbytes)
+{
+ return pth_write (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout)
+{
+ return pth_select (nfd, rset, wset, eset, timeout);
+}
+
+
+ssize_t
+ath_waitpid (pid_t pid, int *status, int options)
+{
+ return pth_waitpid (pid, status, options);
+}
+
+
+int
+ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
+{
+ return pth_accept (s, addr, length_ptr);
+}
+
+
+int
+ath_connect (int s, const struct sockaddr *addr, socklen_t length)
+{
+ return pth_connect (s, addr, length);
+}
+
+int
+ath_sendmsg (int s, const struct msghdr *msg, int flags)
+{
+ /* FIXME: GNU Pth is missing pth_sendmsg. */
+ return sendmsg (s, msg, flags);
+}
+
+
+int
+ath_recvmsg (int s, struct msghdr *msg, int flags)
+{
+ /* FIXME: GNU Pth is missing pth_recvmsg. */
+ return recvmsg (s, msg, flags);
+}
+
diff --git a/branches/gpgme-1-0-branch/gpgme/ath-pthread-compat.c b/branches/gpgme-1-0-branch/gpgme/ath-pthread-compat.c
new file mode 100644
index 00000000..365cf97c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath-pthread-compat.c
@@ -0,0 +1,104 @@
+/* ath-pthread.c - pthread module for self-adapting thread-safeness library
+ * Copyright (C) 2002 g10 Code GmbH
+ *
+ * This file is part of GPGME.
+ *
+ * GPGME is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GPGME is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "ath.h"
+
+/* Need to include pthread_create in our check, as the GNU C library
+ has the pthread_mutex_* functions in their public interface. */
+#pragma weak pthread_create
+#pragma weak pthread_mutex_init
+#pragma weak pthread_mutex_destroy
+#pragma weak pthread_mutex_lock
+#pragma weak pthread_mutex_unlock
+
+/* The lock we take while checking for lazy lock initialization. */
+static pthread_mutex_t check_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if
+ it is not already initialized. */
+static int
+mutex_pthread_init (void **priv, int just_check)
+{
+ int err = 0;
+
+ if (just_check)
+ pthread_mutex_lock (&check_init_lock);
+ if (!*priv || !just_check)
+ {
+ pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
+ if (!lock)
+ err = ENOMEM;
+ if (!err)
+ {
+ err = pthread_mutex_init (lock, NULL);
+ if (err)
+ free (lock);
+ else
+ *priv = lock;
+ }
+ }
+ if (just_check)
+ pthread_mutex_unlock (&check_init_lock);
+ return err;
+}
+
+
+static int
+mutex_pthread_destroy (void *priv)
+{
+ int err = pthread_mutex_destroy ((pthread_mutex_t *) priv);
+ free (priv);
+ return err;
+}
+
+
+static struct ath_ops ath_pthread_ops =
+ {
+ mutex_pthread_init,
+ mutex_pthread_destroy,
+ (int (*) (void *)) pthread_mutex_lock,
+ (int (*) (void *)) pthread_mutex_unlock,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* select */
+ NULL, /* waitpid */
+ NULL, /* accept */
+ NULL, /* connect */
+ NULL, /* sendmsg */
+ NULL /* recvmsg */
+ };
+
+
+struct ath_ops *
+ath_pthread_available (void)
+{
+ /* Need to include pthread_create in our check, as the GNU C library
+ has the pthread_mutex_* functions in their public interface. */
+ if (pthread_create
+ && pthread_mutex_init && pthread_mutex_destroy
+ && pthread_mutex_lock && pthread_mutex_unlock)
+ return &ath_pthread_ops;
+ else
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ath-pthread.c b/branches/gpgme-1-0-branch/gpgme/ath-pthread.c
new file mode 100644
index 00000000..94a4f599
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath-pthread.c
@@ -0,0 +1,175 @@
+/* ath-pthread.c - pthread module for self-adapting thread-safeness library
+ 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. */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <pthread.h>
+
+#include "ath.h"
+
+
+/* The lock we take while checking for lazy lock initialization. */
+static pthread_mutex_t check_init_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if
+ it is not already initialized. */
+static int
+mutex_pthread_init (ath_mutex_t *priv, int just_check)
+{
+ int err = 0;
+
+ if (just_check)
+ pthread_mutex_lock (&check_init_lock);
+ if (!*priv || !just_check)
+ {
+ pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
+ if (!lock)
+ err = ENOMEM;
+ if (!err)
+ {
+ err = pthread_mutex_init (lock, NULL);
+ if (err)
+ free (lock);
+ else
+ *priv = (ath_mutex_t) lock;
+ }
+ }
+ if (just_check)
+ pthread_mutex_unlock (&check_init_lock);
+ return err;
+}
+
+
+void
+ath_init (void)
+{
+ /* Nothing to do. */
+}
+
+
+int
+ath_mutex_init (ath_mutex_t *lock)
+{
+ return mutex_pthread_init (lock, 0);
+}
+
+
+int
+ath_mutex_destroy (ath_mutex_t *lock)
+{
+ int err = mutex_pthread_init (lock, 1);
+ if (!err)
+ {
+ err = pthread_mutex_destroy ((pthread_mutex_t *) *lock);
+ free (*lock);
+ }
+ return err;
+}
+
+
+int
+ath_mutex_lock (ath_mutex_t *lock)
+{
+ int ret = mutex_pthread_init (lock, 1);
+ if (ret)
+ return ret;
+
+ return pthread_mutex_lock ((pthread_mutex_t *) *lock);
+}
+
+
+int
+ath_mutex_unlock (ath_mutex_t *lock)
+{
+ int ret = mutex_pthread_init (lock, 1);
+ if (ret)
+ return ret;
+
+ return pthread_mutex_unlock ((pthread_mutex_t *) *lock);
+}
+
+
+ssize_t
+ath_read (int fd, void *buf, size_t nbytes)
+{
+ return read (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_write (int fd, const void *buf, size_t nbytes)
+{
+ return write (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout)
+{
+ return select (nfd, rset, wset, eset, timeout);
+}
+
+
+ssize_t
+ath_waitpid (pid_t pid, int *status, int options)
+{
+ return waitpid (pid, status, options);
+}
+
+
+int
+ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
+{
+ return accept (s, addr, length_ptr);
+}
+
+
+int
+ath_connect (int s, const struct sockaddr *addr, socklen_t length)
+{
+ return connect (s, addr, length);
+}
+
+int
+ath_sendmsg (int s, const struct msghdr *msg, int flags)
+{
+ return sendmsg (s, msg, flags);
+}
+
+
+int
+ath_recvmsg (int s, struct msghdr *msg, int flags)
+{
+ return recvmsg (s, msg, flags);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ath.c b/branches/gpgme-1-0-branch/gpgme/ath.c
new file mode 100644
index 00000000..6390ecc4
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath.c
@@ -0,0 +1,142 @@
+/* ath.c - Thread-safeness library.
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "ath.h"
+
+
+#define MUTEX_UNLOCKED ((ath_mutex_t) 0)
+#define MUTEX_LOCKED ((ath_mutex_t) 1)
+#define MUTEX_DESTROYED ((ath_mutex_t) 2)
+
+
+int
+ath_mutex_init (ath_mutex_t *lock)
+{
+#ifndef NDEBUG
+ *lock = MUTEX_UNLOCKED;
+#endif
+ return 0;
+}
+
+
+int
+ath_mutex_destroy (ath_mutex_t *lock)
+{
+#ifndef NDEBUG
+ assert (*lock == MUTEX_UNLOCKED);
+
+ *lock = MUTEX_DESTROYED;
+#endif
+ return 0;
+}
+
+
+int
+ath_mutex_lock (ath_mutex_t *lock)
+{
+#ifndef NDEBUG
+ assert (*lock == MUTEX_UNLOCKED);
+
+ *lock = MUTEX_LOCKED;
+#endif
+ return 0;
+}
+
+
+int
+ath_mutex_unlock (ath_mutex_t *lock)
+{
+#ifndef NDEBUG
+ assert (*lock == MUTEX_LOCKED);
+
+ *lock = MUTEX_UNLOCKED;
+#endif
+ return 0;
+}
+
+
+ssize_t
+ath_read (int fd, void *buf, size_t nbytes)
+{
+ return read (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_write (int fd, const void *buf, size_t nbytes)
+{
+ return write (fd, buf, nbytes);
+}
+
+
+ssize_t
+ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout)
+{
+ return select (nfd, rset, wset, eset, timeout);
+}
+
+
+ssize_t
+ath_waitpid (pid_t pid, int *status, int options)
+{
+ return waitpid (pid, status, options);
+}
+
+
+int
+ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr)
+{
+ return accept (s, addr, length_ptr);
+}
+
+
+int
+ath_connect (int s, const struct sockaddr *addr, socklen_t length)
+{
+ return connect (s, addr, length);
+}
+
+
+int
+ath_sendmsg (int s, const struct msghdr *msg, int flags)
+{
+ return sendmsg (s, msg, flags);
+}
+
+
+int
+ath_recvmsg (int s, struct msghdr *msg, int flags)
+{
+ return recvmsg (s, msg, flags);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ath.h b/branches/gpgme-1-0-branch/gpgme/ath.h
new file mode 100644
index 00000000..04dfb285
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ath.h
@@ -0,0 +1,106 @@
+/* ath.h - Interfaces for thread-safeness library.
+ 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. */
+
+#ifndef ATH_H
+#define ATH_H
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#else
+# include <sys/time.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+/* Define _ATH_EXT_SYM_PREFIX if you want to give all external symbols
+ a prefix. */
+#define _ATH_EXT_SYM_PREFIX _gpgme_
+
+#ifdef _ATH_EXT_SYM_PREFIX
+#define _ATH_PREFIX1(x,y) x ## y
+#define _ATH_PREFIX2(x,y) _ATH_PREFIX1(x,y)
+#define _ATH_PREFIX(x) _ATH_PREFIX2(_ATH_EXT_SYM_PREFIX,x)
+#define ath_mutex_init _ATH_PREFIX(ath_mutex_init)
+#define ath_mutex_destroy _ATH_PREFIX(ath_mutex_destroy)
+#define ath_mutex_lock _ATH_PREFIX(ath_mutex_lock)
+#define ath_mutex_unlock _ATH_PREFIX(ath_mutex_unlock)
+#define ath_read _ATH_PREFIX(ath_read)
+#define ath_write _ATH_PREFIX(ath_write)
+#define ath_select _ATH_PREFIX(ath_select)
+#define ath_waitpid _ATH_PREFIX(ath_waitpid)
+#define ath_connect _ATH_PREFIX(ath_connect)
+#define ath_accept _ATH_PREFIX(ath_accept)
+#define ath_sendmsg _ATH_PREFIX(ath_sendmsg)
+#define ath_recvmsg _ATH_PREFIX(ath_recvmsg)
+#endif
+
+
+typedef void *ath_mutex_t;
+#define ATH_MUTEX_INITIALIZER 0;
+
+/* Functions for mutual exclusion. */
+int ath_mutex_init (ath_mutex_t *mutex);
+int ath_mutex_destroy (ath_mutex_t *mutex);
+int ath_mutex_lock (ath_mutex_t *mutex);
+int ath_mutex_unlock (ath_mutex_t *mutex);
+
+/* Replacement for the POSIX functions, which can be used to allow
+ other (user-level) threads to run. */
+ssize_t ath_read (int fd, void *buf, size_t nbytes);
+ssize_t ath_write (int fd, const void *buf, size_t nbytes);
+ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout);
+ssize_t ath_waitpid (pid_t pid, int *status, int options);
+int ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr);
+int ath_connect (int s, const struct sockaddr *addr, socklen_t length);
+int ath_sendmsg (int s, const struct msghdr *msg, int flags);
+int ath_recvmsg (int s, struct msghdr *msg, int flags);
+
+#define _ATH_COMPAT
+#ifdef _ATH_COMPAT
+struct ath_ops
+{
+ int (*mutex_init) (void **priv, int just_check);
+ int (*mutex_destroy) (void *priv);
+ int (*mutex_lock) (void *priv);
+ int (*mutex_unlock) (void *priv);
+ ssize_t (*read) (int fd, void *buf, size_t nbytes);
+ ssize_t (*write) (int fd, const void *buf, size_t nbytes);
+ ssize_t (*select) (int nfd, fd_set *rset, fd_set *wset, fd_set *eset,
+ struct timeval *timeout);
+ ssize_t (*waitpid) (pid_t pid, int *status, int options);
+ int (*accept) (int s, struct sockaddr *addr, socklen_t *length_ptr);
+ int (*connect) (int s, const struct sockaddr *addr, socklen_t length);
+ int (*sendmsg) (int s, const struct msghdr *msg, int flags);
+ int (*recvmsg) (int s, struct msghdr *msg, int flags);
+};
+
+/* Initialize the any-thread package. */
+#define ath_init _ATH_PREFIX(ath_init)
+void ath_init (void);
+
+/* Used by ath_pkg_init. */
+#define ath_pthread_available _ATH_PREFIX(ath_pthread_available)
+struct ath_ops *ath_pthread_available (void);
+#define ath_pth_available _ATH_PREFIX(ath_pth_available)
+struct ath_ops *ath_pth_available (void);
+#endif
+
+#endif /* ATH_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/context.h b/branches/gpgme-1-0-branch/gpgme/context.h
new file mode 100644
index 00000000..64c5276c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/context.h
@@ -0,0 +1,111 @@
+/* context.h - Definitions for a GPGME context.
+ 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 CONTEXT_H
+#define CONTEXT_H
+
+#include "gpgme.h"
+#include "engine.h"
+#include "wait.h"
+
+
+/* Operations might require to remember arbitrary information and data
+ objects during invocations of the status handler. The
+ ctx_op_data structure provides a generic framework to hook in
+ such additional data. */
+typedef enum
+ {
+ OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
+ OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
+ OPDATA_VERIFY, OPDATA_TRUSTLIST
+ } ctx_op_data_id_t;
+
+
+struct ctx_op_data
+{
+ /* The next element in the linked list, or NULL if this is the last
+ element. */
+ struct ctx_op_data *next;
+
+ /* The type of the hook data, which can be used by a routine to
+ lookup the hook data. */
+ ctx_op_data_id_t type;
+
+ /* The function to release HOOK and all its associated resources.
+ Can be NULL if no special dealllocation routine is necessary. */
+ void (*cleanup) (void *hook);
+
+ /* The hook that points to the operation data. */
+ void *hook;
+};
+typedef struct ctx_op_data *ctx_op_data_t;
+
+
+/* The context defines an environment in which crypto operations can
+ be performed (sequentially). */
+struct gpgme_context
+{
+ /* The protocol used by this context. */
+ gpgme_protocol_t protocol;
+
+ /* The running engine process. */
+ engine_t engine;
+
+ /* True if armor mode should be used. */
+ unsigned int use_armor : 1;
+
+ /* True if text mode should be used. */
+ unsigned int use_textmode : 1;
+
+ /* Flags for keylist mode. */
+ gpgme_keylist_mode_t keylist_mode;
+
+ /* Number of certs to be included. */
+ unsigned int include_certs;
+
+ /* The number of keys in signers. */
+ unsigned int signers_len;
+
+ /* Size of the following array. */
+ unsigned int signers_size;
+ gpgme_key_t *signers;
+
+ /* The locale for the pinentry. */
+ char *lc_ctype;
+ char *lc_messages;
+
+ /* The operation data hooked into the context. */
+ ctx_op_data_t op_data;
+
+ /* The user provided passphrase callback and its hook value. */
+ gpgme_passphrase_cb_t passphrase_cb;
+ void *passphrase_cb_value;
+
+ /* The user provided progress callback and its hook value. */
+ gpgme_progress_cb_t progress_cb;
+ void *progress_cb_value;
+
+ /* A list of file descriptors in active use by the current
+ operation. */
+ struct fd_table fdt;
+ struct gpgme_io_cbs io_cbs;
+};
+
+#endif /* CONTEXT_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/conversion.c b/branches/gpgme-1-0-branch/gpgme/conversion.c
new file mode 100644
index 00000000..12a58229
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/conversion.c
@@ -0,0 +1,411 @@
+/* conversion.c - String conversion helper functions.
+ 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 <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+
+
+#define atoi_1(p) (*(p) - '0' )
+#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
+#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
+
+
+
+/* Convert two hexadecimal digits from STR to the value they
+ represent. Returns -1 if one of the characters is not a
+ hexadecimal digit. */
+int
+_gpgme_hextobyte (const char *str)
+{
+ int val = 0;
+ int i;
+
+#define NROFHEXDIGITS 2
+ for (i = 0; i < NROFHEXDIGITS; i++)
+ {
+ if (*str >= '0' && *str <= '9')
+ val += *str - '0';
+ else if (*str >= 'A' && *str <= 'F')
+ val += 10 + *str - 'A';
+ else if (*str >= 'a' && *str <= 'f')
+ val += 10 + *str - 'a';
+ else
+ return -1;
+ if (i < NROFHEXDIGITS - 1)
+ val *= 16;
+ str++;
+ }
+ return val;
+}
+
+
+/* Decode the C formatted string SRC and store the result in the
+ buffer *DESTP which is LEN bytes long. If LEN is zero, then a
+ large enough buffer is allocated with malloc and *DESTP is set to
+ the result. Currently, LEN is only used to specify if allocation
+ is desired or not, the caller is expected to make sure that *DESTP
+ is large enough if LEN is not zero. */
+gpgme_error_t
+_gpgme_decode_c_string (const char *src, char **destp, size_t len)
+{
+ char *dest;
+
+ /* Set up the destination buffer. */
+ if (len)
+ {
+ if (len < strlen (src) + 1)
+ return gpg_error (GPG_ERR_INTERNAL);
+
+ dest = *destp;
+ }
+ else
+ {
+ /* The converted string will never be larger than the original
+ string. */
+ dest = malloc (strlen (src) + 1);
+ if (!dest)
+ return gpg_error_from_errno (errno);
+
+ *destp = dest;
+ }
+
+ /* Convert the string. */
+ while (*src)
+ {
+ if (*src != '\\')
+ {
+ *(dest++) = *(src++);
+ continue;
+ }
+
+ switch (src[1])
+ {
+#define DECODE_ONE(match,result) \
+ case match: \
+ src += 2; \
+ *(dest++) = result; \
+ break;
+
+ DECODE_ONE ('\'', '\'');
+ DECODE_ONE ('\"', '\"');
+ DECODE_ONE ('\?', '\?');
+ DECODE_ONE ('\\', '\\');
+ DECODE_ONE ('a', '\a');
+ DECODE_ONE ('b', '\b');
+ DECODE_ONE ('f', '\f');
+ DECODE_ONE ('n', '\n');
+ DECODE_ONE ('r', '\r');
+ DECODE_ONE ('t', '\t');
+ DECODE_ONE ('v', '\v');
+
+ case 'x':
+ {
+ int val = _gpgme_hextobyte (&src[2]);
+
+ if (val == -1)
+ {
+ /* Should not happen. */
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ if (*src)
+ *(dest++) = *(src++);
+ if (*src)
+ *(dest++) = *(src++);
+ }
+ else
+ {
+ if (!val)
+ {
+ /* A binary zero is not representable in a C
+ string. */
+ *(dest++) = '\\';
+ *(dest++) = '0';
+ }
+ else
+ *((unsigned char *) dest++) = val;
+ src += 4;
+ }
+ }
+ break;
+
+ default:
+ {
+ /* Should not happen. */
+ *(dest++) = *(src++);
+ *(dest++) = *(src++);
+ }
+ }
+ }
+ *(dest++) = 0;
+
+ return 0;
+}
+
+
+/* Decode the percent escaped string SRC and store the result in the
+ buffer *DESTP which is LEN bytes long. If LEN is zero, then a
+ large enough buffer is allocated with malloc and *DESTP is set to
+ the result. Currently, LEN is only used to specify if allocation
+ is desired or not, the caller is expected to make sure that *DESTP
+ is large enough if LEN is not zero. */
+gpgme_error_t
+_gpgme_decode_percent_string (const char *src, char **destp, size_t len)
+{
+ char *dest;
+
+ /* Set up the destination buffer. */
+ if (len)
+ {
+ if (len < strlen (src) + 1)
+ return gpg_error (GPG_ERR_INTERNAL);
+
+ dest = *destp;
+ }
+ else
+ {
+ /* The converted string will never be larger than the original
+ string. */
+ dest = malloc (strlen (src) + 1);
+ if (!dest)
+ return gpg_error_from_errno (errno);
+
+ *destp = dest;
+ }
+
+ /* Convert the string. */
+ while (*src)
+ {
+ if (*src != '%')
+ {
+ *(dest++) = *(src++);
+ continue;
+ }
+ else
+ {
+ int val = _gpgme_hextobyte (&src[1]);
+
+ if (val == -1)
+ {
+ /* Should not happen. */
+ *(dest++) = *(src++);
+ if (*src)
+ *(dest++) = *(src++);
+ if (*src)
+ *(dest++) = *(src++);
+ }
+ else
+ {
+ if (!val)
+ {
+ /* A binary zero is not representable in a C
+ string. */
+ *(dest++) = '\\';
+ *(dest++) = '0';
+ }
+ else
+ *((unsigned char *) dest++) = val;
+ src += 3;
+ }
+ }
+ }
+ *(dest++) = 0;
+
+ return 0;
+}
+
+
+/* Parse the string TIMESTAMP into a time_t. The string may either be
+ seconds since Epoch or in the ISO 8601 format like
+ "20390815T143012". Returns 0 for an empty string or seconds since
+ Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
+ point to the next non-parsed character in TIMESTRING. */
+time_t
+_gpgme_parse_timestamp (const char *timestamp, char **endp)
+{
+ /* Need to skip leading spaces, because that is what strtoul does
+ but not our ISO 8601 checking code. */
+ while (*timestamp && *timestamp== ' ')
+ timestamp++;
+ if (!*timestamp)
+ return 0;
+
+ if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
+ {
+ struct tm buf;
+ int year;
+
+ year = atoi_4 (timestamp);
+ if (year < 1900)
+ return (time_t)(-1);
+
+ /* Fixme: We would better use a configure test to see whether
+ mktime can handle dates beyond 2038. */
+ if (sizeof (time_t) <= 4 && year >= 2038)
+ return (time_t)2145914603; /* 2037-12-31 23:23:23 */
+
+ memset (&buf, 0, sizeof buf);
+ buf.tm_year = year - 1900;
+ buf.tm_mon = atoi_2 (timestamp+4) - 1;
+ buf.tm_mday = atoi_2 (timestamp+6);
+ buf.tm_hour = atoi_2 (timestamp+9);
+ buf.tm_min = atoi_2 (timestamp+11);
+ buf.tm_sec = atoi_2 (timestamp+13);
+
+ if (endp)
+ *endp = (char*)(timestamp + 15);
+#ifdef HAVE_TIMEGM
+ return timegm (&buf);
+#else
+ {
+ time_t tim;
+
+ putenv ("TZ=UTC");
+ tim = mktime (&buf);
+#ifdef __GNUC__
+#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
+#endif
+ return tim;
+ }
+#endif /* !HAVE_TIMEGM */
+ }
+ else
+ return (time_t)strtoul (timestamp, endp, 10);
+}
+
+
+
+
+static struct
+{
+ char *name;
+ gpgme_error_t err;
+} gnupg_errors[] =
+ {
+ { "EOF", GPG_ERR_EOF },
+ { "No_Error", GPG_ERR_NO_ERROR },
+ { "General_Error", GPG_ERR_GENERAL },
+ { "Out_Of_Core", GPG_ERR_ENOMEM },
+ { "Invalid_Value", GPG_ERR_INV_VALUE },
+ { "IO_Error", GPG_ERR_GENERAL },
+ { "Resource_Limit", GPG_ERR_RESOURCE_LIMIT },
+ { "Internal_Error", GPG_ERR_INTERNAL },
+ { "Bad_Certificate", GPG_ERR_BAD_CERT },
+ { "Bad_Certificate_Chain", GPG_ERR_BAD_CERT_CHAIN},
+ { "Missing_Certificate", GPG_ERR_MISSING_CERT },
+ { "No_Data", GPG_ERR_NO_DATA },
+ { "Bad_Signature", GPG_ERR_BAD_SIGNATURE },
+ { "Not_Implemented", GPG_ERR_NOT_IMPLEMENTED },
+ { "Conflict", GPG_ERR_CONFLICT },
+ { "Bug", GPG_ERR_BUG },
+ { "Read_Error", GPG_ERR_GENERAL },
+ { "Write_Error", GPG_ERR_GENERAL },
+ { "Invalid_Line", GPG_ERR_GENERAL },
+ { "Incomplete_Line", GPG_ERR_INCOMPLETE_LINE },
+ { "Invalid_Response", GPG_ERR_INV_RESPONSE },
+ { "Agent_Error", GPG_ERR_AGENT },
+ { "No_Public_Key", GPG_ERR_NO_PUBKEY },
+ { "No_Secret_Key", GPG_ERR_NO_SECKEY },
+ { "File_Open_Error", GPG_ERR_GENERAL },
+ { "File_Create_Error", GPG_ERR_GENERAL },
+ { "File_Error", GPG_ERR_GENERAL },
+ { "Not_Supported", GPG_ERR_NOT_SUPPORTED },
+ { "Invalid_Data", GPG_ERR_INV_DATA },
+ { "Assuan_Server_Fault", GPG_ERR_ASSUAN_SERVER_FAULT },
+ { "Assuan_Error", GPG_ERR_ASSUAN },
+ { "Invalid_Session_Key", GPG_ERR_INV_SESSION_KEY },
+ { "Invalid_Sexp", GPG_ERR_INV_SEXP },
+ { "Unsupported_Algorithm", GPG_ERR_UNSUPPORTED_ALGORITHM },
+ { "No_PIN_Entry", GPG_ERR_NO_PIN_ENTRY },
+ { "PIN_Entry_Error", GPG_ERR_NO_PIN_ENTRY },
+ { "Bad_PIN", GPG_ERR_BAD_PIN },
+ { "Bad_Passphrase", GPG_ERR_BAD_PASSPHRASE },
+ { "Invalid_Name", GPG_ERR_INV_NAME },
+ { "Bad_Public_Key", GPG_ERR_BAD_PUBKEY },
+ { "Bad_Secret_Key", GPG_ERR_BAD_SECKEY },
+ { "Bad_Data", GPG_ERR_BAD_DATA },
+ { "Invalid_Parameter", GPG_ERR_INV_PARAMETER },
+ { "Tribute_to_D_A", GPG_ERR_TRIBUTE_TO_D_A },
+ { "No_Dirmngr", GPG_ERR_NO_DIRMNGR },
+ { "Dirmngr_Error", GPG_ERR_DIRMNGR },
+ { "Certificate_Revoked", GPG_ERR_CERT_REVOKED },
+ { "No_CRL_Known", GPG_ERR_NO_CRL_KNOWN },
+ { "CRL_Too_Old", GPG_ERR_CRL_TOO_OLD },
+ { "Line_Too_Long", GPG_ERR_LINE_TOO_LONG },
+ { "Not_Trusted", GPG_ERR_NOT_TRUSTED },
+ { "Canceled", GPG_ERR_CANCELED },
+ { "Bad_CA_Certificate", GPG_ERR_BAD_CA_CERT },
+ { "Certificate_Expired", GPG_ERR_CERT_EXPIRED },
+ { "Certificate_Too_Young", GPG_ERR_CERT_TOO_YOUNG },
+ { "Unsupported_Certificate", GPG_ERR_UNSUPPORTED_CERT },
+ { "Unknown_Sexp", GPG_ERR_UNKNOWN_SEXP },
+ { "Unsupported_Protection", GPG_ERR_UNSUPPORTED_PROTECTION },
+ { "Corrupted_Protection", GPG_ERR_CORRUPTED_PROTECTION },
+ { "Ambiguous_Name", GPG_ERR_AMBIGUOUS_NAME },
+ { "Card_Error", GPG_ERR_CARD },
+ { "Card_Reset", GPG_ERR_CARD_RESET },
+ { "Card_Removed", GPG_ERR_CARD_REMOVED },
+ { "Invalid_Card", GPG_ERR_INV_CARD },
+ { "Card_Not_Present", GPG_ERR_CARD_NOT_PRESENT },
+ { "No_PKCS15_App", GPG_ERR_NO_PKCS15_APP },
+ { "Not_Confirmed", GPG_ERR_NOT_CONFIRMED },
+ { "Configuration_Error", GPG_ERR_CONFIGURATION },
+ { "No_Policy_Match", GPG_ERR_NO_POLICY_MATCH },
+ { "Invalid_Index", GPG_ERR_INV_INDEX },
+ { "Invalid_Id", GPG_ERR_INV_ID },
+ { "No_Scdaemon", GPG_ERR_NO_SCDAEMON },
+ { "Scdaemon_Error", GPG_ERR_SCDAEMON },
+ { "Unsupported_Protocol", GPG_ERR_UNSUPPORTED_PROTOCOL },
+ { "Bad_PIN_Method", GPG_ERR_BAD_PIN_METHOD },
+ { "Card_Not_Initialized", GPG_ERR_CARD_NOT_INITIALIZED },
+ { "Unsupported_Operation", GPG_ERR_UNSUPPORTED_OPERATION },
+ { "Wrong_Key_Usage", GPG_ERR_WRONG_KEY_USAGE }
+ };
+
+
+gpgme_error_t
+_gpgme_map_gnupg_error (char *err)
+{
+ unsigned int i;
+
+ /* Future version of GnuPG might return the error code directly, so
+ we first test for a a numerical value and use that verbatim.
+ Note that this numerical value might be followed by an
+ underschore and the textual representation of the error code. */
+ if (*err >= '0' && *err <= '9')
+ return strtoul (err, NULL, 10);
+
+ /* Well, this is a token, use the mapping table to get the error.
+ The drawback is that we won't receive an error source and have to
+ use GPG as source. */
+ for (i = 0; i < DIM (gnupg_errors); i++)
+ if (!strcmp (gnupg_errors[i].name, err))
+ return gpg_err_make (GPG_ERR_SOURCE_GPG, gnupg_errors[i].err);
+
+ return gpg_err_make (GPG_ERR_SOURCE_GPG, GPG_ERR_GENERAL);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data-compat.c b/branches/gpgme-1-0-branch/gpgme/data-compat.c
new file mode 100644
index 00000000..c8d31e71
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data-compat.c
@@ -0,0 +1,208 @@
+/* data-compat.c - Compatibility interfaces for data objects.
+ Copyright (C) 2002, 2003, 2004 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 <errno.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "data.h"
+#include "util.h"
+
+
+/* Create a new data buffer filled with LENGTH bytes starting from
+ OFFSET within the file FNAME or stream STREAM (exactly one must be
+ non-zero). */
+gpgme_error_t
+gpgme_data_new_from_filepart (gpgme_data_t *dh, const char *fname,
+ FILE *stream, off_t offset, size_t length)
+{
+ gpgme_error_t err;
+ char *buf = NULL;
+ int res;
+
+ if (stream && fname)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (fname)
+ stream = fopen (fname, "rb");
+ if (!stream)
+ return gpg_error_from_errno (errno);
+
+#ifdef HAVE_FSEEKO
+ res = fseeko (stream, offset, SEEK_SET);
+#else
+ /* FIXME: Check for overflow, or at least bail at compilation. */
+ res = fseek (stream, offset, SEEK_SET);
+#endif
+
+ if (res)
+ {
+ int saved_errno = errno;
+ if (fname)
+ fclose (stream);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ buf = malloc (length);
+ if (!buf)
+ {
+ int saved_errno = errno;
+ if (fname)
+ fclose (stream);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ while (fread (buf, length, 1, stream) < 1
+ && ferror (stream) && errno == EINTR);
+ if (ferror (stream))
+ {
+ int saved_errno = errno;
+ if (buf)
+ free (buf);
+ if (fname)
+ fclose (stream);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ if (fname)
+ fclose (stream);
+
+ err = gpgme_data_new (dh);
+ if (err)
+ {
+ if (buf)
+ free (buf);
+ return err;
+ }
+
+ (*dh)->data.mem.buffer = buf;
+ (*dh)->data.mem.size = length;
+ (*dh)->data.mem.length = length;
+ return 0;
+}
+
+
+/* Create a new data buffer filled with the content of file FNAME.
+ COPY must be non-zero (delayed reads are not supported yet). */
+gpgme_error_t
+gpgme_data_new_from_file (gpgme_data_t *dh, const char *fname, int copy)
+{
+ struct stat statbuf;
+
+ if (!fname || !copy)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (stat (fname, &statbuf) < 0)
+ return gpg_error_from_errno (errno);
+
+ return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size);
+}
+
+
+static int
+gpgme_error_to_errno (gpgme_error_t err)
+{
+ int no = gpg_err_code_to_errno (err);
+
+ if (no)
+ {
+ errno = no;
+ return -1;
+ }
+
+ switch (gpg_err_code (err))
+ {
+ case GPG_ERR_EOF:
+ return 0;
+ case GPG_ERR_INV_VALUE:
+ errno = EINVAL;
+ return -1;
+ case GPG_ERR_NOT_SUPPORTED:
+ errno = EOPNOTSUPP;
+ return -1;
+ default:
+ /* FIXME: Yeah, well. */
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+
+static ssize_t
+old_user_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ size_t amt;
+ gpgme_error_t err = (*dh->data.old_user.cb) (dh->data.old_user.handle,
+ buffer, size, &amt);
+ if (err)
+ return gpgme_error_to_errno (err);
+ return amt;
+}
+
+
+static off_t
+old_user_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ gpgme_error_t err;
+ if (whence != SEEK_SET || offset)
+ return EINVAL;
+ err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL);
+ if (err)
+ return gpgme_error_to_errno (err);
+ return 0;
+}
+
+
+static struct _gpgme_data_cbs old_user_cbs =
+ {
+ old_user_read,
+ NULL,
+ old_user_seek,
+ NULL
+ };
+
+
+/* Create a new data buffer which retrieves the data from the callback
+ function READ_CB. */
+gpgme_error_t
+gpgme_data_new_with_read_cb (gpgme_data_t *dh,
+ int (*read_cb) (void *, char *, size_t, size_t *),
+ void *read_cb_value)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &old_user_cbs);
+ if (err)
+ return err;
+
+ (*dh)->data.old_user.cb = read_cb;
+ (*dh)->data.old_user.handle = read_cb_value;
+ return 0;
+}
+
+
+gpgme_error_t
+gpgme_data_rewind (gpgme_data_t dh)
+{
+ return (gpgme_data_seek (dh, 0, SEEK_SET) == -1)
+ ? gpg_error_from_errno (errno) : 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data-fd.c b/branches/gpgme-1-0-branch/gpgme/data-fd.c
new file mode 100644
index 00000000..b120ca00
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data-fd.c
@@ -0,0 +1,69 @@
+/* data-fd.c - A file descripor based data object.
+ 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 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 <unistd.h>
+#include <sys/types.h>
+
+#include "data.h"
+
+
+static ssize_t
+fd_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ return read (dh->data.fd, buffer, size);
+}
+
+
+static ssize_t
+fd_write (gpgme_data_t dh, const void *buffer, size_t size)
+{
+ return write (dh->data.fd, buffer, size);
+}
+
+
+static off_t
+fd_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ return lseek (dh->data.fd, offset, whence);
+}
+
+
+static struct _gpgme_data_cbs fd_cbs =
+ {
+ fd_read,
+ fd_write,
+ fd_seek,
+ NULL
+ };
+
+
+gpgme_error_t
+gpgme_data_new_from_fd (gpgme_data_t *dh, int fd)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &fd_cbs);
+ if (err)
+ return err;
+
+ (*dh)->data.fd = fd;
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data-mem.c b/branches/gpgme-1-0-branch/gpgme/data-mem.c
new file mode 100644
index 00000000..6d11899b
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data-mem.c
@@ -0,0 +1,223 @@
+/* data-mem.c - A memory based data object.
+ 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 <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <string.h>
+
+#include "data.h"
+#include "util.h"
+
+
+static ssize_t
+mem_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ size_t amt = dh->data.mem.length - dh->data.mem.offset;
+ const char *src;
+
+ if (!amt)
+ return 0;
+
+ if (size < amt)
+ amt = size;
+
+ src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer;
+ memcpy (buffer, src + dh->data.mem.offset, amt);
+ dh->data.mem.offset += amt;
+ return amt;
+}
+
+
+static ssize_t
+mem_write (gpgme_data_t dh, const void *buffer, size_t size)
+{
+ size_t unused;
+
+ if (!dh->data.mem.buffer && dh->data.mem.orig_buffer)
+ {
+ size_t new_size = dh->data.mem.size;
+ char *new_buffer;
+
+ if (new_size < dh->data.mem.offset + size)
+ new_size = dh->data.mem.offset + size;
+
+ new_buffer = malloc (new_size);
+ if (!new_buffer)
+ return -1;
+ memcpy (new_buffer, dh->data.mem.orig_buffer, dh->data.mem.length);
+
+ dh->data.mem.buffer = new_buffer;
+ dh->data.mem.size = new_size;
+ }
+
+ unused = dh->data.mem.size - dh->data.mem.offset;
+ if (unused < size)
+ {
+ /* Allocate a large enough buffer with exponential backoff. */
+#define INITIAL_ALLOC 512
+ size_t new_size = dh->data.mem.size
+ ? (2 * dh->data.mem.size) : INITIAL_ALLOC;
+ char *new_buffer;
+
+ if (new_size < dh->data.mem.offset + size)
+ new_size = dh->data.mem.offset + size;
+
+ new_buffer = realloc (dh->data.mem.buffer, new_size);
+ if (!new_buffer && new_size > dh->data.mem.offset + size)
+ {
+ /* Maybe we were too greedy, try again. */
+ new_size = dh->data.mem.offset + size;
+ new_buffer = realloc (dh->data.mem.buffer, new_size);
+ }
+ if (!new_buffer)
+ return -1;
+ dh->data.mem.buffer = new_buffer;
+ dh->data.mem.size = new_size;
+ }
+
+ memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size);
+ dh->data.mem.offset += size;
+ if (dh->data.mem.length < dh->data.mem.offset)
+ dh->data.mem.length = dh->data.mem.offset;
+ return size;
+}
+
+
+static off_t
+mem_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (offset < 0 || offset > dh->data.mem.length)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ dh->data.mem.offset = offset;
+ break;
+ case SEEK_CUR:
+ if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset)
+ || (offset < 0 && dh->data.mem.offset < -offset))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ dh->data.mem.offset += offset;
+ break;
+ case SEEK_END:
+ if (offset > 0 || -offset > dh->data.mem.length)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ dh->data.mem.offset = dh->data.mem.length - offset;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ return dh->data.mem.offset;
+}
+
+
+static void
+mem_release (gpgme_data_t dh)
+{
+ if (dh->data.mem.buffer)
+ free (dh->data.mem.buffer);
+}
+
+
+static struct _gpgme_data_cbs mem_cbs =
+ {
+ mem_read,
+ mem_write,
+ mem_seek,
+ mem_release
+ };
+
+
+gpgme_error_t
+gpgme_data_new (gpgme_data_t *dh)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &mem_cbs);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+/* Create a new data buffer filled with SIZE bytes starting from
+ BUFFER. If COPY is zero, copying is delayed until necessary, and
+ the data is taken from the original location when needed. */
+gpgme_error_t
+gpgme_data_new_from_mem (gpgme_data_t *dh, const char *buffer,
+ size_t size, int copy)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &mem_cbs);
+ if (err)
+ return err;
+
+ if (copy)
+ {
+ char *bufcpy = malloc (size);
+ if (!bufcpy)
+ _gpgme_data_release (*dh);
+ memcpy (bufcpy, buffer, size);
+ (*dh)->data.mem.buffer = bufcpy;
+ }
+ else
+ (*dh)->data.mem.orig_buffer = buffer;
+
+ (*dh)->data.mem.size = size;
+ (*dh)->data.mem.length = size;
+ return 0;
+}
+
+
+char *
+gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len)
+{
+ char *str = NULL;
+
+ if (!dh || dh->cbs != &mem_cbs)
+ return NULL;
+
+ str = dh->data.mem.buffer;
+ if (!str && dh->data.mem.orig_buffer)
+ {
+ str = malloc (dh->data.mem.length);
+ if (!str)
+ return NULL;
+ memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length);
+ }
+
+ if (r_len)
+ *r_len = dh->data.mem.length;
+
+ return str;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data-stream.c b/branches/gpgme-1-0-branch/gpgme/data-stream.c
new file mode 100644
index 00000000..3abecaaf
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data-stream.c
@@ -0,0 +1,87 @@
+/* data-stream.c - A stream based data object.
+ Copyright (C) 2002, 2004 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 <stdio.h>
+#include <sys/types.h>
+
+#include "data.h"
+
+
+static ssize_t
+stream_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ size_t amt = fread (buffer, 1, size, dh->data.stream);
+ if (amt > 0)
+ return amt;
+ return ferror (dh->data.stream) ? -1 : 0;
+}
+
+
+static ssize_t
+stream_write (gpgme_data_t dh, const void *buffer, size_t size)
+{
+ size_t amt = fwrite (buffer, 1, size, dh->data.stream);
+ if (amt > 0)
+ return amt;
+ return ferror (dh->data.stream) ? -1 : 0;
+}
+
+
+static off_t
+stream_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ int err;
+
+#ifdef HAVE_FSEEKO
+ err = fseeko (dh->data.stream, offset, whence);
+#else
+ /* FIXME: Check for overflow, or at least bail at compilation. */
+ err = fseek (dh->data.stream, offset, whence);
+#endif
+
+ if (err)
+ return -1;
+
+ return ftello (dh->data.stream);
+}
+
+
+static struct _gpgme_data_cbs stream_cbs =
+ {
+ stream_read,
+ stream_write,
+ stream_seek,
+ NULL
+ };
+
+
+gpgme_error_t
+gpgme_data_new_from_stream (gpgme_data_t *dh, FILE *stream)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &stream_cbs);
+ if (err)
+ return err;
+
+ (*dh)->data.stream = stream;
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data-user.c b/branches/gpgme-1-0-branch/gpgme/data-user.c
new file mode 100644
index 00000000..6f12c35e
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data-user.c
@@ -0,0 +1,76 @@
+/* data-user.c - A user callback based data object.
+ 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 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 <sys/types.h>
+
+#include "data.h"
+
+
+static ssize_t
+user_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ return (*dh->data.user.cbs->read) (dh->data.user.handle, buffer, size);
+}
+
+
+static ssize_t
+user_write (gpgme_data_t dh, const void *buffer, size_t size)
+{
+ return (*dh->data.user.cbs->write) (dh->data.user.handle, buffer, size);
+}
+
+
+static off_t
+user_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ return (*dh->data.user.cbs->seek) (dh->data.user.handle, offset, whence);
+}
+
+
+static void
+user_release (gpgme_data_t dh)
+{
+ (*dh->data.user.cbs->release) (dh->data.user.handle);
+}
+
+
+static struct _gpgme_data_cbs user_cbs =
+ {
+ user_read,
+ user_write,
+ user_seek,
+ user_release
+ };
+
+
+gpgme_error_t
+gpgme_data_new_from_cbs (gpgme_data_t *dh, gpgme_data_cbs_t cbs, void *handle)
+{
+ gpgme_error_t err = _gpgme_data_new (dh, &user_cbs);
+ if (err)
+ return err;
+
+ (*dh)->data.user.cbs = cbs;
+ (*dh)->data.user.handle = handle;
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data.c b/branches/gpgme-1-0-branch/gpgme/data.c
new file mode 100644
index 00000000..c30e6eca
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data.c
@@ -0,0 +1,242 @@
+/* data.c - An abstraction for data objects.
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gpgme.h"
+#include "data.h"
+#include "util.h"
+#include "ops.h"
+#include "io.h"
+
+
+gpgme_error_t
+_gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs)
+{
+ gpgme_data_t dh;
+
+ if (!r_dh)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ *r_dh = NULL;
+ dh = calloc (1, sizeof (*dh));
+ if (!dh)
+ return gpg_error_from_errno (errno);
+
+ dh->cbs = cbs;
+
+ *r_dh = dh;
+ return 0;
+}
+
+
+void
+_gpgme_data_release (gpgme_data_t dh)
+{
+ if (dh)
+ free (dh);
+}
+
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle DH. Return the number of characters read, 0 on EOF and
+ -1 on error. If an error occurs, errno is set. */
+ssize_t
+gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size)
+{
+ if (!dh)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!dh->cbs->read)
+ {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ return (*dh->cbs->read) (dh, buffer, size);
+}
+
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle DH. Return the number of characters written, or -1 on
+ error. If an error occurs, errno is set. */
+ssize_t
+gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size)
+{
+ if (!dh)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!dh->cbs->write)
+ {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+ return (*dh->cbs->write) (dh, buffer, size);
+}
+
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle DH to OFFSET, relativ to
+ WHENCE. */
+off_t
+gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence)
+{
+ if (!dh)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!dh->cbs->seek)
+ {
+ errno = EOPNOTSUPP;
+ return -1;
+ }
+
+ /* For relative movement, we must take into account the actual
+ position of the read counter. */
+ if (whence == SEEK_CUR)
+ offset -= dh->pending_len;
+
+ offset = (*dh->cbs->seek) (dh, offset, whence);
+ if (offset >= 0)
+ dh->pending_len = 0;
+
+ return offset;
+}
+
+
+/* Release the data object with the handle DH. */
+void
+gpgme_data_release (gpgme_data_t dh)
+{
+ if (!dh)
+ return;
+
+ if (dh->cbs->release)
+ (*dh->cbs->release) (dh);
+ _gpgme_data_release (dh);
+}
+
+
+/* Get the current encoding meta information for the data object with
+ handle DH. */
+gpgme_data_encoding_t
+gpgme_data_get_encoding (gpgme_data_t dh)
+{
+ return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE;
+}
+
+
+/* Set the encoding meta information for the data object with handle
+ DH to ENC. */
+gpgme_error_t
+gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc)
+{
+ if (!dh)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ dh->encoding = enc;
+ return 0;
+}
+
+
+/* Functions to support the wait interface. */
+
+gpgme_error_t
+_gpgme_data_inbound_handler (void *opaque, int fd)
+{
+ gpgme_data_t dh = (gpgme_data_t) opaque;
+ char buffer[BUFFER_SIZE];
+ char *bufp = buffer;
+ ssize_t buflen;
+
+ buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE);
+ if (buflen < 0)
+ return gpg_error_from_errno (errno);
+ if (buflen == 0)
+ {
+ _gpgme_io_close (fd);
+ return 0;
+ }
+
+ do
+ {
+ ssize_t amt = gpgme_data_write (dh, bufp, buflen);
+ if (amt == 0 || (amt < 0 && errno != EINTR))
+ return gpg_error_from_errno (errno);
+ bufp += amt;
+ buflen -= amt;
+ }
+ while (buflen > 0);
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_data_outbound_handler (void *opaque, int fd)
+{
+ gpgme_data_t dh = (gpgme_data_t) opaque;
+ ssize_t nwritten;
+
+ if (!dh->pending_len)
+ {
+ ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE);
+ if (amt < 0)
+ return gpg_error_from_errno (errno);
+ if (amt == 0)
+ {
+ _gpgme_io_close (fd);
+ return 0;
+ }
+ dh->pending_len = amt;
+ }
+
+ nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len);
+ if (nwritten == -1 && errno == EAGAIN)
+ return 0;
+
+ if (nwritten == -1 && errno == EPIPE)
+ {
+ /* Not much we can do. The other end closed the pipe, but we
+ still have data. This should only ever happen if the other
+ end is going to tell us what happened on some other channel.
+ Silently close our end. */
+ _gpgme_io_close (fd);
+ return 0;
+ }
+
+ if (nwritten <= 0)
+ return gpg_error_from_errno (errno);
+
+ if (nwritten < dh->pending_len)
+ memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten);
+ dh->pending_len -= nwritten;
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/data.h b/branches/gpgme-1-0-branch/gpgme/data.h
new file mode 100644
index 00000000..51d89aa8
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/data.h
@@ -0,0 +1,120 @@
+/* data.h - Internal data object abstraction interface.
+ 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 GPGME; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef DATA_H
+#define DATA_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <limits.h>
+
+#include "gpgme.h"
+
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle DH. Return the number of characters read, 0 on EOF and
+ -1 on error. If an error occurs, errno is set. */
+typedef ssize_t (*gpgme_data_read_cb) (gpgme_data_t dh, void *buffer,
+ size_t size);
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle DH. Return the number of characters written, or -1 on
+ error. If an error occurs, errno is set. */
+typedef ssize_t (*gpgme_data_write_cb) (gpgme_data_t dh, const void *buffer,
+ size_t size);
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle DH to OFFSET, relativ to
+ WHENCE. */
+typedef off_t (*gpgme_data_seek_cb) (gpgme_data_t dh, off_t offset,
+ int whence);
+
+/* Release the data object with the handle DH. */
+typedef void (*gpgme_data_release_cb) (gpgme_data_t dh);
+
+struct _gpgme_data_cbs
+{
+ gpgme_data_read_cb read;
+ gpgme_data_write_cb write;
+ gpgme_data_seek_cb seek;
+ gpgme_data_release_cb release;
+};
+
+struct gpgme_data
+{
+ struct _gpgme_data_cbs *cbs;
+ gpgme_data_encoding_t encoding;
+
+#ifdef PIPE_BUF
+#define BUFFER_SIZE PIPE_BUF
+#else
+#ifdef _POSIX_PIPE_BUF
+#define BUFFER_SIZE _POSIX_PIPE_BUF
+#else
+#define BUFFER_SIZE 512
+#endif
+#endif
+ char pending[BUFFER_SIZE];
+ int pending_len;
+
+ union
+ {
+ /* For gpgme_data_new_from_fd. */
+ int fd;
+
+ /* For gpgme_data_new_from_stream. */
+ FILE *stream;
+
+ /* For gpgme_data_new_from_cbs. */
+ struct
+ {
+ gpgme_data_cbs_t cbs;
+ void *handle;
+ } user;
+
+ /* For gpgme_data_new_from_mem. */
+ struct
+ {
+ char *buffer;
+ const char *orig_buffer;
+ /* Allocated size of BUFFER. */
+ size_t size;
+ size_t length;
+ off_t offset;
+ } mem;
+
+ /* For gpgme_data_new_from_read_cb. */
+ struct
+ {
+ int (*cb) (void *, char *, size_t, size_t *);
+ void *handle;
+ } old_user;
+ } data;
+};
+
+
+gpgme_error_t _gpgme_data_new (gpgme_data_t *r_dh,
+ struct _gpgme_data_cbs *cbs);
+
+void _gpgme_data_release (gpgme_data_t dh);
+
+#endif /* DATA_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/debug.c b/branches/gpgme-1-0-branch/gpgme/debug.c
new file mode 100644
index 00000000..f9136462
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/debug.c
@@ -0,0 +1,220 @@
+/* debug.c - helpful output in desperate situations
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifndef HAVE_DOSISH_SYSTEM
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+#endif
+#include <assert.h>
+
+#include "util.h"
+#include "sema.h"
+
+
+/* Lock to serialize initialization of the debug output subsystem and
+ output of actual debug messages. */
+DEFINE_STATIC_LOCK (debug_lock);
+
+/* The amount of detail requested by the user, per environment
+ variable GPGME_DEBUG. */
+static int debug_level;
+
+/* The output stream for the debug messages. */
+static FILE *errfp;
+
+
+/* Remove leading and trailing white spaces. */
+static char *
+trim_spaces (char *str)
+{
+ char *string, *p, *mark;
+
+ string = str;
+ /* Find first non space character. */
+ for (p = string; *p && isspace (*(unsigned char *) p); p++)
+ ;
+ /* Move characters. */
+ for (mark = NULL; (*string = *p); string++, p++)
+ if (isspace (*(unsigned char *) p))
+ {
+ if (!mark)
+ mark = string;
+ }
+ else
+ mark = NULL;
+ if (mark)
+ *mark = '\0'; /* Remove trailing spaces. */
+
+ return str;
+}
+
+
+static void
+debug_init (void)
+{
+ static int initialized;
+
+ LOCK (debug_lock);
+ if (!initialized)
+ {
+ gpgme_error_t err;
+ char *e;
+ const char *s1, *s2;;
+
+ err = _gpgme_getenv ("GPGME_DEBUG", &e);
+ if (err)
+ {
+ UNLOCK (debug_lock);
+ return;
+ }
+
+ initialized = 1;
+ errfp = stderr;
+ if (e)
+ {
+ debug_level = atoi (e);
+ s1 = strchr (e, ':');
+ if (s1)
+ {
+#ifndef HAVE_DOSISH_SYSTEM
+ if (getuid () == geteuid ())
+ {
+#endif
+ char *p;
+ FILE *fp;
+
+ s1++;
+ if (!(s2 = strchr (s1, ':')))
+ s2 = s1 + strlen (s1);
+ p = malloc (s2 - s1 + 1);
+ if (p)
+ {
+ memcpy (p, s1, s2 - s1);
+ p[s2-s1] = 0;
+ trim_spaces (p);
+ fp = fopen (p,"a");
+ if (fp)
+ {
+ setvbuf (fp, NULL, _IOLBF, 0);
+ errfp = fp;
+ }
+ free (p);
+ }
+#ifndef HAVE_DOSISH_SYSTEM
+ }
+#endif
+ }
+ free (e);
+ }
+
+ if (debug_level > 0)
+ fprintf (errfp, "gpgme_debug: level=%d\n", debug_level);
+ }
+ UNLOCK (debug_lock);
+}
+
+
+/* Log the formatted string FORMAT at debug level LEVEL or higher. */
+void
+_gpgme_debug (int level, const char *format, ...)
+{
+ va_list arg_ptr;
+
+ debug_init ();
+ if (debug_level < level)
+ return;
+
+ va_start (arg_ptr, format);
+ LOCK (debug_lock);
+ vfprintf (errfp, format, arg_ptr);
+ va_end (arg_ptr);
+ if(format && *format && format[strlen (format) - 1] != '\n')
+ putc ('\n', errfp);
+ UNLOCK (debug_lock);
+ fflush (errfp);
+}
+
+
+/* Start a new debug line in *LINE, logged at level LEVEL or higher,
+ and starting with the formatted string FORMAT. */
+void
+_gpgme_debug_begin (void **line, int level, const char *format, ...)
+{
+ va_list arg_ptr;
+
+ debug_init ();
+ if (debug_level < level)
+ {
+ /* Disable logging of this line. */
+ *line = NULL;
+ return;
+ }
+
+ va_start (arg_ptr, format);
+ vasprintf ((char **) line, format, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+/* Add the formatted string FORMAT to the debug line *LINE. */
+void
+_gpgme_debug_add (void **line, const char *format, ...)
+{
+ va_list arg_ptr;
+ char *toadd;
+ char *result;
+
+ if (!*line)
+ return;
+
+ va_start (arg_ptr, format);
+ vasprintf (&toadd, format, arg_ptr);
+ va_end (arg_ptr);
+ asprintf (&result, "%s%s", *(char **) line, toadd);
+ free (*line);
+ free (toadd);
+ *line = result;
+}
+
+
+/* Finish construction of *LINE and send it to the debug output
+ stream. */
+void
+_gpgme_debug_end (void **line)
+{
+ if (!*line)
+ return;
+
+ /* The smallest possible level is 1, so force logging here by
+ using that. */
+ _gpgme_debug (1, "%s", *line);
+ free (*line);
+ *line = NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/debug.h b/branches/gpgme-1-0-branch/gpgme/debug.h
new file mode 100644
index 00000000..4bc42cfa
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/debug.h
@@ -0,0 +1,110 @@
+/* debug.h - interface to debugging functions
+ * 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
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+/* Log the formatted string FORMAT at debug level LEVEL or higher. */
+void _gpgme_debug (int level, const char *format, ...);
+
+/* Start a new debug line in *LINE, logged at level LEVEL or higher,
+ and starting with the formatted string FORMAT. */
+void _gpgme_debug_begin (void **helper, int level, const char *format, ...);
+
+/* Add the formatted string FORMAT to the debug line *LINE. */
+void _gpgme_debug_add (void **helper, const char *format, ...);
+
+/* Finish construction of *LINE and send it to the debug output
+ stream. */
+void _gpgme_debug_end (void **helper);
+
+/* Indirect stringification, requires __STDC__ to work. */
+#define STRINGIFY(v) #v
+#define XSTRINGIFY(v) STRINGIFY(v)
+
+#if 0
+/* Only works in GNU. */
+#define DEBUG(fmt, arg...) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__) , ##arg)
+#define DEBUG_BEGIN(hlp, lvl, fmt, arg...) \
+ _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \
+ XSTRINGIFY (__LINE__) , ##arg)
+#define DEBUG_ADD(hlp, fmt, arg...) \
+ _gpgme_debug_add (&(hlp), fmt , ##arg)
+#define DEBUG_END(hlp, fmt, arg...) \
+ _gpgme_debug_add (&(hlp), fmt , ##arg); \
+ _gpgme_debug_end (&(hlp))
+#elif 0
+/* Only works in C99. */
+#define DEBUG0(fmt) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__))
+#define DEBUG(fmt, ...) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), __VA_ARGS__)
+#define DEBUG_BEGIN(hlp, lvl, fmt) \
+ _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \
+ XSTRINGIFY (__LINE__))
+#define DEBUG_BEGINX(hlp, lvl, fmt, ...) \
+ _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \
+ XSTRINGIFY (__LINE__), __VA_ARGS__)
+#define DEBUG_ADD0(hlp, fmt) \
+ _gpgme_debug_add (&(hlp), fmt)
+#define DEBUG_ADD(hlp, fmt, ...) \
+ _gpgme_debug_add (&(hlp), fmt, __VA_ARGS__)
+#define DEBUG_END(hlp, fmt) \
+ _gpgme_debug_add (&(hlp), fmt); \
+ _gpgme_debug_end (&(hlp))
+#define DEBUG_ENDX(hlp, fmt, ...) \
+ _gpgme_debug_add (&(hlp), fmt, __VA_ARGS__); \
+ _gpgme_debug_end (&(hlp))
+#else
+/* This finally works everywhere, horror. */
+#define DEBUG0(fmt) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__))
+#define DEBUG1(fmt,a) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), (a))
+#define DEBUG2(fmt,a,b) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), (a), (b))
+#define DEBUG3(fmt,a,b,c) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), (a), (b), \
+ (c))
+#define DEBUG4(fmt,a,b,c,d) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), (a), (b), \
+ (c), (d))
+#define DEBUG5(fmt,a,b,c,d,e) \
+ _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), (a), (b), \
+ (c), (d), (e))
+#define DEBUG_BEGIN(hlp,lvl,fmt) \
+ _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__))
+#define DEBUG_ADD0(hlp,fmt) \
+ _gpgme_debug_add (&(hlp), fmt)
+#define DEBUG_ADD1(hlp,fmt,a) \
+ _gpgme_debug_add (&(hlp), fmt, (a))
+#define DEBUG_ADD2(hlp,fmt,a,b) \
+ _gpgme_debug_add (&(hlp), fmt, (a), (b))
+#define DEBUG_ADD3(hlp,fmt,a,b,c) \
+ _gpgme_debug_add (&(hlp), fmt, (a), (b), (c))
+#define DEBUG_END(hlp,fmt) \
+ _gpgme_debug_add (&(hlp), fmt); \
+ _gpgme_debug_end (&(hlp))
+#endif
+
+#define DEBUG_ENABLED(hlp) (!!(hlp))
+
+#endif /* DEBUG_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/decrypt-verify.c b/branches/gpgme-1-0-branch/gpgme/decrypt-verify.c
new file mode 100644
index 00000000..ef7f79b8
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/decrypt-verify.c
@@ -0,0 +1,102 @@
+/* decrypt-verify.c - Decrypt and verify function.
+ 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 "gpgme.h"
+#include "ops.h"
+
+
+static gpgme_error_t
+decrypt_verify_status_handler (void *priv, gpgme_status_code_t code,
+ char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_decrypt_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_verify_status_handler (priv, code, args);
+ return err;
+}
+
+
+static gpgme_error_t
+decrypt_verify_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_data_t cipher, gpgme_data_t plain)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_decrypt_init_result (ctx);
+ if (err)
+ return err;
+
+ err = _gpgme_op_verify_init_result (ctx);
+ if (err)
+ return err;
+
+ if (!cipher)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!plain)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ _gpgme_engine_set_status_handler (ctx->engine,
+ decrypt_verify_status_handler, ctx);
+
+ return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
+}
+
+
+/* Decrypt ciphertext CIPHER and make a signature verification within
+ CTX and store the resulting plaintext in PLAIN. */
+gpgme_error_t
+gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
+ gpgme_data_t plain)
+{
+ return decrypt_verify_start (ctx, 0, cipher, plain);
+}
+
+
+/* Decrypt ciphertext CIPHER and make a signature verification within
+ CTX and store the resulting plaintext in PLAIN. */
+gpgme_error_t
+gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher,
+ gpgme_data_t plain)
+{
+ gpgme_error_t err = decrypt_verify_start (ctx, 1, cipher, plain);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/decrypt.c b/branches/gpgme-1-0-branch/gpgme/decrypt.c
new file mode 100644
index 00000000..b37d28e9
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/decrypt.c
@@ -0,0 +1,238 @@
+/* decrypt.c - Decrypt function.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2002, 2003, 2004 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 <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_decrypt_result result;
+
+ int okay;
+ int failed;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+
+ if (opd->result.unsupported_algorithm)
+ free (opd->result.unsupported_algorithm);
+}
+
+
+gpgme_decrypt_result_t
+gpgme_op_decrypt_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+gpgme_error_t
+_gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+ char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_passphrase_status_handler (priv, code, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_EOF:
+ /* FIXME: These error values should probably be attributed to
+ the underlying crypto engine (as error source). */
+ if (opd->failed)
+ return gpg_error (GPG_ERR_DECRYPT_FAILED);
+ else if (!opd->okay)
+ return gpg_error (GPG_ERR_NO_DATA);
+ break;
+
+ case GPGME_STATUS_DECRYPTION_OKAY:
+ opd->okay = 1;
+ break;
+
+ case GPGME_STATUS_DECRYPTION_FAILED:
+ opd->failed = 1;
+ break;
+
+ case GPGME_STATUS_ERROR:
+ /* Note that this is an informational status code which should
+ not lead to an error return unless it is something not
+ related to the backend. */
+ {
+ const char d_alg[] = "decrypt.algorithm";
+ const char u_alg[] = "Unsupported_Algorithm";
+ const char k_alg[] = "decrypt.keyusage";
+
+ if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
+ {
+ args += sizeof (d_alg) - 1;
+ while (*args == ' ')
+ args++;
+
+ if (!strncmp (args, u_alg, sizeof (u_alg) - 1))
+ {
+ char *end;
+
+ args += sizeof (u_alg) - 1;
+ while (*args == ' ')
+ args++;
+
+ end = strchr (args, ' ');
+ if (end)
+ *end = '\0';
+
+ if (!(*args == '?' && *(args + 1) == '\0'))
+ {
+ opd->result.unsupported_algorithm = strdup (args);
+ if (!opd->result.unsupported_algorithm)
+ return gpg_error_from_errno (errno);
+ }
+ }
+ }
+ else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
+ {
+ args += sizeof (k_alg) - 1;
+ while (*args == ' ')
+ args++;
+
+ err = _gpgme_map_gnupg_error (args);
+ if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
+ opd->result.wrong_key_usage = 1;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static gpgme_error_t
+decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_decrypt_status_handler (priv, code, args);
+ return err;
+}
+
+
+gpgme_error_t
+_gpgme_op_decrypt_init_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+
+ return _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook,
+ sizeof (*opd), release_op_data);
+}
+
+
+static gpgme_error_t
+decrypt_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_data_t cipher, gpgme_data_t plain)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_decrypt_init_result (ctx);
+ if (err)
+ return err;
+
+ if (!cipher)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!plain)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (err)
+ return err;
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ _gpgme_engine_set_status_handler (ctx->engine, decrypt_status_handler, ctx);
+
+ return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain);
+}
+
+
+gpgme_error_t
+gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
+ gpgme_data_t plain)
+{
+ return decrypt_start (ctx, 0, cipher, plain);
+}
+
+
+/* Decrypt ciphertext CIPHER within CTX and store the resulting
+ plaintext in PLAIN. */
+gpgme_error_t
+gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain)
+{
+ gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/delete.c b/branches/gpgme-1-0-branch/gpgme/delete.c
new file mode 100644
index 00000000..30dd4500
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/delete.c
@@ -0,0 +1,108 @@
+/* delete.c - Delete a key.
+ 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 <errno.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+static gpgme_error_t
+delete_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ if (code == GPGME_STATUS_DELETE_PROBLEM)
+ {
+ enum delete_problem
+ {
+ DELETE_No_Problem = 0,
+ DELETE_No_Such_Key = 1,
+ DELETE_Must_Delete_Secret_Key = 2,
+ DELETE_Ambiguous_Specification = 3
+ };
+ long problem;
+ char *tail;
+
+ errno = 0;
+ problem = strtol (args, &tail, 0);
+ if (errno || (*tail && *tail != ' '))
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ switch (problem)
+ {
+ case DELETE_No_Problem:
+ break;
+
+ case DELETE_No_Such_Key:
+ return gpg_error (GPG_ERR_NO_PUBKEY);
+
+ case DELETE_Must_Delete_Secret_Key:
+ return gpg_error (GPG_ERR_CONFLICT);
+
+ case DELETE_Ambiguous_Specification:
+ return gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+
+ default:
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+delete_start (gpgme_ctx_t ctx, int synchronous, const gpgme_key_t key,
+ int allow_secret)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, delete_status_handler, ctx);
+
+ return _gpgme_engine_op_delete (ctx->engine, key, allow_secret);
+}
+
+
+/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
+ keys are also deleted. */
+gpgme_error_t
+gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
+ int allow_secret)
+{
+ return delete_start (ctx, 0, key, allow_secret);
+}
+
+
+/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
+ keys are also deleted. */
+gpgme_error_t
+gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret)
+{
+ gpgme_error_t err = delete_start (ctx, 1, key, allow_secret);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/edit.c b/branches/gpgme-1-0-branch/gpgme/edit.c
new file mode 100644
index 00000000..8c538f3a
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/edit.c
@@ -0,0 +1,169 @@
+/* edit.c - Key edit function.
+ 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 <stdlib.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ /* The user callback function and its hook value. */
+ gpgme_edit_cb_t fnc;
+ void *fnc_value;
+} *op_data_t;
+
+
+static gpgme_error_t
+edit_status_handler (void *priv, gpgme_status_code_t status, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_passphrase_status_handler (priv, status, args);
+ if (err)
+ return err;
+
+ err = _gpgme_progress_status_handler (priv, status, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ return (*opd->fnc) (opd->fnc_value, status, args, -1);
+}
+
+
+static gpgme_error_t
+command_handler (void *priv, gpgme_status_code_t status, const char *args,
+ int fd)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ int processed = 0;
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_passphrase_command_handler_internal (ctx, status, args,
+ fd, &processed);
+ if (err)
+ return err;
+ }
+
+ if (!processed)
+ {
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ return (*opd->fnc) (opd->fnc_value, status, args, fd);
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (!fnc || !out)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_EDIT, &hook, sizeof (*opd), NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ opd->fnc = fnc;
+ opd->fnc_value = fnc_value;
+
+ err = _gpgme_engine_set_command_handler (ctx->engine, command_handler,
+ ctx, out);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, edit_status_handler, ctx);
+
+ return _gpgme_engine_op_edit (ctx->engine, type, key, out, ctx);
+}
+
+
+gpgme_error_t
+gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+ return edit_start (ctx, 0, 0, key, fnc, fnc_value, out);
+}
+
+
+/* Edit the key KEY. Send status and command requests to FNC and
+ output of edit commands to OUT. */
+gpgme_error_t
+gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+ gpgme_error_t err = edit_start (ctx, 1, 0, key, fnc, fnc_value, out);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+gpgme_error_t
+gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out)
+{
+ return edit_start (ctx, 0, 1, key, fnc, fnc_value, out);
+}
+
+
+/* Edit the card for the key KEY. Send status and command requests to
+ FNC and output of edit commands to OUT. */
+gpgme_error_t
+gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out)
+{
+ gpgme_error_t err = edit_start (ctx, 1, 1, key, fnc, fnc_value, out);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/encrypt-sign.c b/branches/gpgme-1-0-branch/gpgme/encrypt-sign.c
new file mode 100644
index 00000000..ae4b594a
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/encrypt-sign.c
@@ -0,0 +1,109 @@
+/* encrypt-sign.c - encrypt and verify functions
+ 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 "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+static gpgme_error_t
+encrypt_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_encrypt_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_sign_status_handler (priv, code, args);
+ return err;
+}
+
+
+static gpgme_error_t
+encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ if (!plain)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!cipher || !recp)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_encrypt_init_result (ctx);
+ if (err)
+ return err;
+
+ err = _gpgme_op_sign_init_result (ctx);
+ if (err)
+ return err;
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ _gpgme_engine_set_status_handler (ctx->engine,
+ encrypt_sign_status_handler, ctx);
+
+ return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain,
+ cipher, ctx->use_armor,
+ ctx /* FIXME */);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ with the signers in CTX. */
+gpgme_error_t
+gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return encrypt_sign_start (ctx, 0, recp, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ with the signers in CTX. */
+gpgme_error_t
+gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ gpgme_error_t err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/encrypt.c b/branches/gpgme-1-0-branch/gpgme/encrypt.c
new file mode 100644
index 00000000..6eb177e0
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/encrypt.c
@@ -0,0 +1,221 @@
+/* encrypt.c - Encrypt function.
+ 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 <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_encrypt_result result;
+
+ /* A pointer to the next pointer of the last invalid recipient in
+ the list. This makes appending new invalid recipients painless
+ while preserving the order. */
+ gpgme_invalid_key_t *lastp;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+ gpgme_invalid_key_t invalid_recipient = opd->result.invalid_recipients;
+
+ while (invalid_recipient)
+ {
+ gpgme_invalid_key_t next = invalid_recipient->next;
+ if (invalid_recipient->fpr)
+ free (invalid_recipient->fpr);
+ invalid_recipient = next;
+ }
+}
+
+
+gpgme_encrypt_result_t
+gpgme_op_encrypt_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
+ opd = hook;
+
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+gpgme_error_t
+_gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code,
+ char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_EOF:
+ if (opd->result.invalid_recipients)
+ return gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+ break;
+
+ case GPGME_STATUS_INV_RECP:
+ err = _gpgme_parse_inv_recp (args, opd->lastp);
+ if (err)
+ return err;
+
+ opd->lastp = &(*opd->lastp)->next;
+ break;
+
+ case GPGME_STATUS_NO_RECP:
+ /* Should not happen, because we require at least one recipient. */
+ return gpg_error (GPG_ERR_GENERAL);
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_passphrase_status_handler (priv, code, args);
+ return err;
+}
+
+
+static gpgme_error_t
+encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ return _gpgme_progress_status_handler (priv, code, args)
+ || _gpgme_encrypt_status_handler (priv, code, args);
+}
+
+
+gpgme_error_t
+_gpgme_op_encrypt_init_result (gpgme_ctx_t ctx)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, sizeof (*opd),
+ release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ opd->lastp = &opd->result.invalid_recipients;
+ return 0;
+}
+
+
+static gpgme_error_t
+encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ gpgme_error_t err;
+ int symmetric = 0;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_encrypt_init_result (ctx);
+ if (err)
+ return err;
+
+ if (!recp)
+ symmetric = 1;
+
+ if (!plain)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!cipher)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (recp && ! *recp)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (symmetric && ctx->passphrase_cb)
+ {
+ /* Symmetric encryption requires a passphrase. */
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ _gpgme_engine_set_status_handler (ctx->engine,
+ symmetric
+ ? encrypt_sym_status_handler
+ : encrypt_status_handler,
+ ctx);
+
+ return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher,
+ ctx->use_armor);
+}
+
+
+gpgme_error_t
+gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ return encrypt_start (ctx, 0, recp, flags, plain, cipher);
+}
+
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. */
+gpgme_error_t
+gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher)
+{
+ gpgme_error_t err = encrypt_start (ctx, 1, recp, flags, plain, cipher);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/engine-backend.h b/branches/gpgme-1-0-branch/gpgme/engine-backend.h
new file mode 100644
index 00000000..32fd242e
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/engine-backend.h
@@ -0,0 +1,97 @@
+/* engine-backend.h - A crypto backend for the engine interface.
+ 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. */
+
+#ifndef ENGINE_BACKEND_H
+#define ENGINE_BACKEND_H
+
+#include "engine.h"
+
+/* FIXME: Correct check? */
+#ifdef GPGSM_PATH
+#define ENABLE_GPGSM 1
+#endif
+
+struct engine_ops
+{
+ /* Static functions. */
+ const char *(*get_file_name) (void);
+ const char *(*get_version) (void);
+ const char *(*get_req_version) (void);
+ gpgme_error_t (*new) (void **r_engine,
+ const char *lc_ctype, const char *lc_messages);
+
+ /* Member functions. */
+ void (*release) (void *engine);
+ void (*set_status_handler) (void *engine, engine_status_handler_t fnc,
+ void *fnc_value);
+ gpgme_error_t (*set_command_handler) (void *engine,
+ engine_command_handler_t fnc,
+ void *fnc_value, gpgme_data_t data);
+ gpgme_error_t (*set_colon_line_handler) (void *engine,
+ engine_colon_line_handler_t fnc,
+ void *fnc_value);
+ gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph,
+ gpgme_data_t plain);
+ gpgme_error_t (*delete) (void *engine, gpgme_key_t key, int allow_secret);
+ gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key,
+ gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */);
+ gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph,
+ int use_armor);
+ gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph,
+ int use_armor, gpgme_ctx_t ctx /* FIXME */);
+ gpgme_error_t (*export) (void *engine, const char *pattern,
+ unsigned int reserved, gpgme_data_t keydata,
+ int use_armor);
+ gpgme_error_t (*export_ext) (void *engine, const char *pattern[],
+ unsigned int reserved, gpgme_data_t keydata,
+ int use_armor);
+ gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor,
+ gpgme_data_t pubkey, gpgme_data_t seckey);
+ gpgme_error_t (*import) (void *engine, gpgme_data_t keydata);
+ gpgme_error_t (*keylist) (void *engine, const char *pattern,
+ int secret_only, gpgme_keylist_mode_t mode);
+ gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[],
+ int secret_only, int reserved,
+ gpgme_keylist_mode_t mode);
+ gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out,
+ gpgme_sig_mode_t mode, int use_armor,
+ int use_textmode,
+ int include_certs, gpgme_ctx_t ctx /* FIXME */);
+ gpgme_error_t (*trustlist) (void *engine, const char *pattern);
+ gpgme_error_t (*verify) (void *engine, gpgme_data_t sig,
+ gpgme_data_t signed_text,
+ gpgme_data_t plaintext);
+
+ void (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs);
+ void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data);
+
+ gpgme_error_t (*cancel) (void *engine);
+};
+
+
+extern struct engine_ops _gpgme_engine_ops_gpg; /* OpenPGP. */
+#ifdef ENABLE_GPGSM
+extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */
+#endif
+
+#endif /* ENGINE_BACKEND_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/engine-gpgsm.c b/branches/gpgme-1-0-branch/gpgme/engine-gpgsm.c
new file mode 100644
index 00000000..0138fdf7
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/engine-gpgsm.c
@@ -0,0 +1,1595 @@
+/* engine-gpgsm.c - GpgSM engine.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2002, 2003, 2004 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 <string.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <unistd.h>
+#include <locale.h>
+#include <fcntl.h> /* FIXME */
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "ops.h"
+#include "wait.h"
+#include "io.h"
+#include "sema.h"
+
+#include "assuan.h"
+#include "status-table.h"
+#include "debug.h"
+
+#include "engine-backend.h"
+
+
+typedef struct
+{
+ int fd; /* FD we talk about. */
+ int dir; /* Inbound/Outbound, maybe given implicit? */
+ void *data; /* Handler-specific data. */
+ void *tag; /* ID from the user for gpgme_remove_io_callback. */
+} iocb_data_t;
+
+
+struct engine_gpgsm
+{
+ ASSUAN_CONTEXT assuan_ctx;
+
+ iocb_data_t status_cb;
+
+ /* Input, output etc are from the servers perspective. */
+ iocb_data_t input_cb;
+ int input_fd_server;
+
+ iocb_data_t output_cb;
+ int output_fd_server;
+
+ iocb_data_t message_cb;
+ int message_fd_server;
+
+ struct
+ {
+ engine_status_handler_t fnc;
+ void *fnc_value;
+ } status;
+
+ struct
+ {
+ engine_colon_line_handler_t fnc;
+ void *fnc_value;
+ struct
+ {
+ unsigned char *line;
+ int linesize;
+ int linelen;
+ } attic;
+ int any; /* any data line seen */
+ } colon;
+
+ struct gpgme_io_cbs io_cbs;
+};
+
+typedef struct engine_gpgsm *engine_gpgsm_t;
+
+
+static const char *
+gpgsm_get_version (void)
+{
+ static const char *gpgsm_version;
+ DEFINE_STATIC_LOCK (gpgsm_version_lock);
+
+ LOCK (gpgsm_version_lock);
+ if (!gpgsm_version)
+ gpgsm_version = _gpgme_get_program_version (_gpgme_get_gpgsm_path ());
+ UNLOCK (gpgsm_version_lock);
+
+ return gpgsm_version;
+}
+
+
+static const char *
+gpgsm_get_req_version (void)
+{
+ return NEED_GPGSM_VERSION;
+}
+
+
+static void
+close_notify_handler (int fd, void *opaque)
+{
+ engine_gpgsm_t gpgsm = opaque;
+
+ assert (fd != -1);
+ if (gpgsm->status_cb.fd == fd)
+ {
+ if (gpgsm->status_cb.tag)
+ (*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);
+ 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);
+ 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);
+ gpgsm->message_cb.fd = -1;
+ }
+}
+
+
+static gpgme_error_t
+map_assuan_error (AssuanError err)
+{
+ if (!err)
+ return 0;
+
+ if (err == -1)
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ /* New code will use gpg_error_t values. */
+ if (gpg_err_source (err))
+ return (gpgme_error_t) err;
+
+ /* Legacy code will use old values. */
+ switch (err)
+ {
+ case ASSUAN_No_Error:
+ return gpg_error (GPG_ERR_NO_ERROR);
+ case ASSUAN_General_Error:
+ return gpg_error (GPG_ERR_GENERAL);
+ case ASSUAN_Out_Of_Core:
+ return gpg_error (GPG_ERR_ENOMEM);
+ case ASSUAN_Invalid_Value:
+ return gpg_error (GPG_ERR_INV_VALUE);
+ case ASSUAN_Timeout:
+ return gpg_error (GPG_ERR_ETIMEDOUT);
+ case ASSUAN_Read_Error:
+ return gpg_error (GPG_ERR_GENERAL);
+ case ASSUAN_Write_Error:
+ return gpg_error (GPG_ERR_GENERAL);
+
+ case ASSUAN_Problem_Starting_Server:
+ case ASSUAN_Not_A_Server:
+ case ASSUAN_Not_A_Client:
+ case ASSUAN_Nested_Commands:
+ case ASSUAN_No_Data_Callback:
+ case ASSUAN_No_Inquire_Callback:
+ case ASSUAN_Connect_Failed:
+ case ASSUAN_Accept_Failed:
+ case ASSUAN_Invalid_Command:
+ case ASSUAN_Unknown_Command:
+ case ASSUAN_Syntax_Error:
+ case ASSUAN_Parameter_Error:
+ case ASSUAN_Parameter_Conflict:
+ case ASSUAN_No_Input:
+ case ASSUAN_No_Output:
+ case ASSUAN_No_Data_Available:
+ case ASSUAN_Too_Much_Data:
+ case ASSUAN_Inquire_Unknown:
+ case ASSUAN_Inquire_Error:
+ case ASSUAN_Invalid_Option:
+ case ASSUAN_Unexpected_Status:
+ case ASSUAN_Unexpected_Data:
+ case ASSUAN_Invalid_Status:
+ return gpg_error (GPG_ERR_ASSUAN);
+
+ case ASSUAN_Invalid_Response:
+ return gpg_error (GPG_ERR_INV_RESPONSE);
+
+ case ASSUAN_Not_Implemented:
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ case ASSUAN_Line_Too_Long:
+ return gpg_error (GPG_ERR_LINE_TOO_LONG);
+ case ASSUAN_Line_Not_Terminated:
+ return gpg_error (GPG_ERR_INCOMPLETE_LINE);
+ case ASSUAN_Canceled:
+ return gpg_error (GPG_ERR_CANCELED);
+
+ case ASSUAN_Unsupported_Algorithm:
+ return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ case ASSUAN_Server_Resource_Problem:
+ return gpg_error (GPG_ERR_RESOURCE_LIMIT);
+ case ASSUAN_Server_IO_Error:
+ return gpg_error (GPG_ERR_GENERAL);
+ case ASSUAN_Server_Bug:
+ return gpg_error (GPG_ERR_BUG);
+ case ASSUAN_Invalid_Data:
+ return gpg_error (GPG_ERR_INV_DATA);
+ case ASSUAN_Invalid_Index:
+ return gpg_error (GPG_ERR_INV_INDEX);
+ case ASSUAN_Not_Confirmed:
+ return gpg_error (GPG_ERR_NOT_CONFIRMED);
+ case ASSUAN_Bad_Certificate:
+ return gpg_error (GPG_ERR_BAD_CERT);
+ case ASSUAN_Bad_Certificate_Chain:
+ return gpg_error (GPG_ERR_BAD_CERT_CHAIN);
+ case ASSUAN_Missing_Certificate:
+ return gpg_error (GPG_ERR_MISSING_CERT);
+ case ASSUAN_Bad_Signature:
+ return gpg_error (GPG_ERR_BAD_SIGNATURE);
+ case ASSUAN_No_Agent:
+ return gpg_error (GPG_ERR_NO_AGENT);
+ case ASSUAN_Agent_Error:
+ return gpg_error (GPG_ERR_AGENT);
+ case ASSUAN_No_Public_Key:
+ return gpg_error (GPG_ERR_NO_PUBKEY);
+ case ASSUAN_No_Secret_Key:
+ return gpg_error (GPG_ERR_NO_SECKEY);
+ case ASSUAN_Invalid_Name:
+ return gpg_error (GPG_ERR_INV_NAME);
+
+ case ASSUAN_Cert_Revoked:
+ return gpg_error (GPG_ERR_CERT_REVOKED);
+ case ASSUAN_No_CRL_For_Cert:
+ return gpg_error (GPG_ERR_NO_CRL_KNOWN);
+ case ASSUAN_CRL_Too_Old:
+ return gpg_error (GPG_ERR_CRL_TOO_OLD);
+ case ASSUAN_Not_Trusted:
+ return gpg_error (GPG_ERR_NOT_TRUSTED);
+
+ case ASSUAN_Card_Error:
+ return gpg_error (GPG_ERR_CARD);
+ case ASSUAN_Invalid_Card:
+ return gpg_error (GPG_ERR_INV_CARD);
+ case ASSUAN_No_PKCS15_App:
+ return gpg_error (GPG_ERR_NO_PKCS15_APP);
+ case ASSUAN_Card_Not_Present:
+ return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
+ case ASSUAN_Invalid_Id:
+ return gpg_error (GPG_ERR_INV_ID);
+ default:
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+}
+
+
+static gpgme_error_t
+gpgsm_cancel (void *engine)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (gpgsm->status_cb.fd != -1)
+ _gpgme_io_close (gpgsm->status_cb.fd);
+ if (gpgsm->input_cb.fd != -1)
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ if (gpgsm->output_cb.fd != -1)
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ if (gpgsm->message_cb.fd != -1)
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ if (gpgsm->assuan_ctx)
+ {
+ assuan_disconnect (gpgsm->assuan_ctx);
+ gpgsm->assuan_ctx = NULL;
+ }
+
+ return 0;
+}
+
+
+static void
+gpgsm_release (void *engine)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ if (!gpgsm)
+ return;
+
+ gpgsm_cancel (engine);
+
+ free (gpgsm->colon.attic.line);
+ free (gpgsm);
+}
+
+
+static gpgme_error_t
+gpgsm_new (void **engine, const char *lc_ctype, const char *lc_messages)
+{
+ gpgme_error_t err = 0;
+ engine_gpgsm_t gpgsm;
+ char *argv[3];
+ int fds[2];
+ int child_fds[4];
+ char *dft_display = NULL;
+ char dft_ttyname[64];
+ char *dft_ttytype = NULL;
+ char *optstr;
+ int fdlist[5];
+ int nfds;
+
+ gpgsm = calloc (1, sizeof *gpgsm);
+ if (!gpgsm)
+ return gpg_error_from_errno (errno);
+
+ gpgsm->status_cb.fd = -1;
+ gpgsm->status_cb.tag = 0;
+
+ gpgsm->input_cb.fd = -1;
+ gpgsm->input_cb.tag = 0;
+ gpgsm->input_fd_server = -1;
+ gpgsm->output_cb.fd = -1;
+ gpgsm->output_cb.tag = 0;
+ gpgsm->output_fd_server = -1;
+ gpgsm->message_cb.fd = -1;
+ gpgsm->message_cb.tag = 0;
+ gpgsm->message_fd_server = -1;
+
+ gpgsm->status.fnc = 0;
+ gpgsm->colon.fnc = 0;
+ gpgsm->colon.attic.line = 0;
+ gpgsm->colon.attic.linesize = 0;
+ gpgsm->colon.attic.linelen = 0;
+ gpgsm->colon.any = 0;
+
+ gpgsm->io_cbs.add = NULL;
+ gpgsm->io_cbs.add_priv = NULL;
+ gpgsm->io_cbs.remove = NULL;
+ gpgsm->io_cbs.event = NULL;
+ gpgsm->io_cbs.event_priv = NULL;
+
+ if (_gpgme_io_pipe (fds, 0) < 0)
+ {
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ gpgsm->input_cb.fd = fds[1];
+ gpgsm->input_cb.dir = 0;
+ gpgsm->input_fd_server = fds[0];
+
+ if (_gpgme_io_pipe (fds, 1) < 0)
+ {
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ gpgsm->output_cb.fd = fds[0];
+ gpgsm->output_cb.dir = 1;
+ gpgsm->output_fd_server = fds[1];
+
+ if (_gpgme_io_pipe (fds, 0) < 0)
+ {
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ gpgsm->message_cb.fd = fds[1];
+ gpgsm->message_cb.dir = 0;
+ gpgsm->message_fd_server = fds[0];
+
+ child_fds[0] = gpgsm->input_fd_server;
+ child_fds[1] = gpgsm->output_fd_server;
+ child_fds[2] = gpgsm->message_fd_server;
+ child_fds[3] = -1;
+
+ argv[0] = "gpgsm";
+ argv[1] = "--server";
+ argv[2] = NULL;
+
+ err = assuan_pipe_connect (&gpgsm->assuan_ctx,
+ _gpgme_get_gpgsm_path (), argv, child_fds);
+ /* FIXME: Check error. */
+
+ /* We need to know the fd used by assuan for reads. We do this by
+ using the assumption that the first returned fd from
+ assuan_get_active_fds() is always this one. */
+ nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
+ fdlist, DIM (fdlist));
+ if (nfds < 1)
+ {
+ err = gpg_error (GPG_ERR_GENERAL); /* FIXME */
+ goto leave;
+ }
+ /* We duplicate the file descriptor, so we can close it without
+ disturbing assuan. Alternatively, we could special case
+ status_fd and register/unregister it manually as needed, but this
+ increases code duplication and is more complicated as we can not
+ use the close notifications etc. */
+ gpgsm->status_cb.fd = dup (fdlist[0]);
+ if (gpgsm->status_cb.fd < 0)
+ {
+ err = gpg_error (GPG_ERR_GENERAL); /* FIXME */
+ goto leave;
+ }
+ gpgsm->status_cb.dir = 1;
+ gpgsm->status_cb.data = gpgsm;
+
+ err = _gpgme_getenv ("DISPLAY", &dft_display);
+ if (err)
+ goto leave;
+ if (dft_display)
+ {
+ if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
+ {
+ free (dft_display);
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ free (dft_display);
+
+ err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free (optstr);
+ if (err)
+ {
+ err = map_assuan_error (err);
+ goto leave;
+ }
+ }
+
+ if (isatty (1))
+ {
+ if (ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)))
+ {
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ else
+ {
+ if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
+ {
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ free (optstr);
+ if (err)
+ {
+ err = map_assuan_error (err);
+ goto leave;
+ }
+
+ err = _gpgme_getenv ("TERM", &dft_ttytype);
+ if (err)
+ goto leave;
+ if (dft_ttytype)
+ {
+ if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
+ {
+ free (dft_ttytype);
+ err = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ free (dft_ttytype);
+
+ err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ free (optstr);
+ if (err)
+ {
+ err = map_assuan_error (err);
+ goto leave;
+ }
+ }
+ }
+ }
+
+ if (lc_ctype)
+ {
+ if (asprintf (&optstr, "OPTION lc-ctype=%s", lc_ctype) < 0)
+ err = gpg_error_from_errno (errno);
+ else
+ {
+ err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ free (optstr);
+ if (err)
+ err = map_assuan_error (err);
+ }
+ }
+ if (err)
+ goto leave;
+
+ if (lc_messages)
+ {
+ if (asprintf (&optstr, "OPTION lc-messages=%s", lc_messages) < 0)
+ err = gpg_error_from_errno (errno);
+ else
+ {
+ err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ free (optstr);
+ if (err)
+ err = map_assuan_error (err);
+ }
+ }
+ if (err)
+ goto leave;
+
+ if (!err
+ && (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
+ close_notify_handler, gpgsm)
+ || _gpgme_io_set_close_notify (gpgsm->input_cb.fd,
+ close_notify_handler, gpgsm)
+ || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
+ close_notify_handler, gpgsm)
+ || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
+ close_notify_handler, gpgsm)))
+ {
+ err = gpg_error (GPG_ERR_GENERAL);
+ goto leave;
+ }
+
+ leave:
+ /* Close the server ends of the pipes. Our ends are closed in
+ gpgsm_release(). */
+ if (gpgsm->input_fd_server != -1)
+ _gpgme_io_close (gpgsm->input_fd_server);
+ if (gpgsm->output_fd_server != -1)
+ _gpgme_io_close (gpgsm->output_fd_server);
+ if (gpgsm->message_fd_server != -1)
+ _gpgme_io_close (gpgsm->message_fd_server);
+
+ if (err)
+ gpgsm_release (gpgsm);
+ else
+ *engine = gpgsm;
+
+ return err;
+}
+
+
+/* Forward declaration. */
+static gpgme_status_code_t parse_status (const char *name);
+
+static gpgme_error_t
+gpgsm_assuan_simple_command (ASSUAN_CONTEXT ctx, char *cmd,
+ engine_status_handler_t status_fnc,
+ void *status_fnc_value)
+{
+ AssuanError err;
+ char *line;
+ size_t linelen;
+
+ err = assuan_write_line (ctx, cmd);
+ if (err)
+ return map_assuan_error (err);
+
+ do
+ {
+ err = assuan_read_line (ctx, &line, &linelen);
+ if (err)
+ return map_assuan_error (err);
+
+ if (*line == '#' || !linelen)
+ continue;
+
+ if (linelen >= 2
+ && line[0] == 'O' && line[1] == 'K'
+ && (line[2] == '\0' || line[2] == ' '))
+ return 0;
+ else if (linelen >= 4
+ && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
+ && line[3] == ' ')
+ err = map_assuan_error (atoi (&line[4]));
+ else if (linelen >= 2
+ && line[0] == 'S' && line[1] == ' ')
+ {
+ char *rest;
+ gpgme_status_code_t r;
+
+ rest = strchr (line + 2, ' ');
+ if (!rest)
+ rest = line + linelen; /* set to an empty string */
+ else
+ *(rest++) = 0;
+
+ r = parse_status (line + 2);
+
+ if (r >= 0 && status_fnc)
+ err = status_fnc (status_fnc_value, r, rest);
+ else
+ err = gpg_error (GPG_ERR_GENERAL);
+ }
+ else
+ err = gpg_error (GPG_ERR_GENERAL);
+ }
+ while (!err);
+
+ return err;
+}
+
+
+#define COMMANDLINELEN 40
+static gpgme_error_t
+gpgsm_set_fd (ASSUAN_CONTEXT ctx, const char *which, int fd, const char *opt)
+{
+ char line[COMMANDLINELEN];
+
+ if (opt)
+ snprintf (line, COMMANDLINELEN, "%s FD=%i %s", which, fd, opt);
+ else
+ snprintf (line, COMMANDLINELEN, "%s FD=%i", which, fd);
+
+ return gpgsm_assuan_simple_command (ctx, line, NULL, NULL);
+}
+
+
+static const char *
+map_input_enc (gpgme_data_t d)
+{
+ switch (gpgme_data_get_encoding (d))
+ {
+ case GPGME_DATA_ENCODING_NONE:
+ break;
+ case GPGME_DATA_ENCODING_BINARY:
+ return "--binary";
+ case GPGME_DATA_ENCODING_BASE64:
+ return "--base64";
+ case GPGME_DATA_ENCODING_ARMOR:
+ return "--armor";
+ default:
+ break;
+ }
+ return NULL;
+}
+
+
+static int
+status_cmp (const void *ap, const void *bp)
+{
+ const struct status_table_s *a = ap;
+ const struct status_table_s *b = bp;
+
+ return strcmp (a->name, b->name);
+}
+
+
+static gpgme_status_code_t
+parse_status (const char *name)
+{
+ struct status_table_s t, *r;
+ t.name = name;
+ r = bsearch (&t, status_table, DIM(status_table) - 1,
+ sizeof t, status_cmp);
+ return r ? r->code : -1;
+}
+
+
+static gpgme_error_t
+status_handler (void *opaque, int fd)
+{
+ AssuanError assuan_err;
+ gpgme_error_t err = 0;
+ engine_gpgsm_t gpgsm = opaque;
+ char *line;
+ size_t linelen;
+
+ do
+ {
+ 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);
+ DEBUG3 ("fd %d: error from assuan (%d) getting status line : %s \n",
+ fd, assuan_err, gpg_strerror (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 = gpg_error (GPG_ERR_GENERAL);
+ DEBUG2 ("fd %d: ERR line - mapped to: %s\n",
+ fd, err? gpg_strerror (err):"ok");
+ }
+ else if (linelen >= 2
+ && line[0] == 'O' && line[1] == 'K'
+ && (line[2] == '\0' || line[2] == ' '))
+ {
+ if (gpgsm->status.fnc)
+ err = gpgsm->status.fnc (gpgsm->status.fnc_value,
+ GPGME_STATUS_EOF, "");
+
+ if (!err && gpgsm->colon.fnc && gpgsm->colon.any )
+ {
+ /* 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;
+ err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
+ }
+ _gpgme_io_close (gpgsm->status_cb.fd);
+ DEBUG2 ("fd %d: OK line - final status: %s\n",
+ fd, err? gpg_strerror (err):"ok");
+ return err;
+ }
+ 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
+ we keep it. */
+ /* FIXME We can't use this for binary data because we
+ assume this is a string. For the current usage of colon
+ output it is correct. */
+ unsigned char *src = line + 2;
+ unsigned char *end = line + linelen;
+ unsigned char *dst;
+ unsigned char **aline = &gpgsm->colon.attic.line;
+ int *alinelen = &gpgsm->colon.attic.linelen;
+
+ if (gpgsm->colon.attic.linesize
+ < *alinelen + linelen + 1)
+ {
+ unsigned char *newline = realloc (*aline,
+ *alinelen + linelen + 1);
+ if (!newline)
+ err = gpg_error_from_errno (errno);
+ else
+ {
+ *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 = (unsigned char) _gpgme_hextobyte (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++;
+ }
+ }
+ DEBUG2 ("fd %d: D line; final status: %s\n",
+ fd, err? gpg_strerror (err):"ok");
+ }
+ else if (linelen > 2
+ && line[0] == 'S' && line[1] == ' ')
+ {
+ char *rest;
+ gpgme_status_code_t r;
+
+ rest = strchr (line + 2, ' ');
+ if (!rest)
+ rest = line + linelen; /* set to an empty string */
+ else
+ *(rest++) = 0;
+
+ r = parse_status (line + 2);
+
+ if (r >= 0)
+ {
+ if (gpgsm->status.fnc)
+ err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
+ }
+ else
+ fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
+ DEBUG3 ("fd %d: S line (%s) - final status: %s\n",
+ fd, line+2, err? gpg_strerror (err):"ok");
+ }
+ }
+ while (!err && assuan_pending_line (gpgsm->assuan_ctx));
+
+ return err;
+}
+
+
+static gpgme_error_t
+add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
+{
+ gpgme_error_t err;
+
+ err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
+ iocbd->fd, iocbd->dir,
+ handler, iocbd->data, &iocbd->tag);
+ if (err)
+ return err;
+ if (!iocbd->dir)
+ /* FIXME Kludge around poll() problem. */
+ err = _gpgme_io_set_nonblocking (iocbd->fd);
+ return err;
+}
+
+
+static gpgme_error_t
+start (engine_gpgsm_t gpgsm, const char *command)
+{
+ gpgme_error_t err;
+
+ err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
+ if (!err && gpgsm->input_cb.fd != -1)
+ err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
+ if (!err && gpgsm->output_cb.fd != -1)
+ err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
+ if (!err && gpgsm->message_cb.fd != -1)
+ err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
+
+ if (!err)
+ err = map_assuan_error (assuan_write_line (gpgsm->assuan_ctx, command));
+
+ if (!err)
+ (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, GPGME_EVENT_START, NULL);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ gpgsm->input_cb.data = ciph;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return gpg_error (GPG_ERR_GENERAL); /* FIXME */
+ gpgsm->output_cb.data = plain;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server, 0);
+ if (err)
+ return gpg_error (GPG_ERR_GENERAL); /* FIXME */
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (engine, "DECRYPT");
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+ char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
+ char *linep = fpr;
+ char *line;
+ int length = 8; /* "DELKEYS " */
+
+ if (!fpr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ while (*linep)
+ {
+ length++;
+ if (*linep == '%' || *linep == ' ' || *linep == '+')
+ length += 2;
+ linep++;
+ }
+ length++;
+
+ line = malloc (length);
+ if (!line)
+ return gpg_error_from_errno (errno);
+
+ strcpy (line, "DELKEYS ");
+ linep = &line[8];
+
+ while (*fpr)
+ {
+ switch (*fpr)
+ {
+ case '%':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '5';
+ break;
+ case ' ':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '0';
+ break;
+ case '+':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = 'B';
+ break;
+ default:
+ *(linep++) = *fpr;
+ break;
+ }
+ fpr++;
+ }
+ *linep = '\0';
+
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, line);
+ free (line);
+
+ return err;
+}
+
+
+static gpgme_error_t
+set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
+{
+ gpgme_error_t err = 0;
+ ASSUAN_CONTEXT ctx = gpgsm->assuan_ctx;
+ char *line;
+ int linelen;
+ int invalid_recipients = 0;
+ int i = 0;
+
+ linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
+ line = malloc (10 + 40 + 1);
+ if (!line)
+ return gpg_error_from_errno (errno);
+ strcpy (line, "RECIPIENT ");
+ while (!err && recp[i])
+ {
+ char *fpr;
+ int newlen;
+
+ if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
+ {
+ invalid_recipients++;
+ continue;
+ }
+ fpr = recp[i]->subkeys->fpr;
+
+ newlen = 11 + strlen (fpr);
+ if (linelen < newlen)
+ {
+ char *newline = realloc (line, newlen);
+ if (! newline)
+ {
+ int saved_errno = errno;
+ free (line);
+ return gpg_error_from_errno (saved_errno);
+ }
+ line = newline;
+ linelen = newlen;
+ }
+ strcpy (&line[10], fpr);
+
+ err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
+ gpgsm->status.fnc_value);
+ /* FIXME: This requires more work. */
+ if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+ invalid_recipients++;
+ else if (err)
+ {
+ free (line);
+ return err;
+ }
+ i++;
+ }
+ free (line);
+ return gpg_error (invalid_recipients
+ ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
+}
+
+
+static gpgme_error_t
+gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!recp)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ gpgsm->input_cb.data = plain;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ gpgsm->output_cb.data = ciph;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ use_armor ? "--armor" : 0);
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = set_recipients (gpgsm, recp);
+
+ if (!err)
+ err = start (gpgsm, "ENCRYPT");
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_export (void *engine, const char *pattern, unsigned int reserved,
+ gpgme_data_t keydata, int use_armor)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err = 0;
+ char *cmd;
+
+ if (!gpgsm || reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!pattern)
+ pattern = "";
+
+ cmd = malloc (7 + strlen (pattern) + 1);
+ if (!cmd)
+ return gpg_error_from_errno (errno);
+ strcpy (cmd, "EXPORT ");
+ strcpy (&cmd[7], pattern);
+
+ gpgsm->output_cb.data = keydata;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ use_armor ? "--armor" : 0);
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, cmd);
+ free (cmd);
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved,
+ gpgme_data_t keydata, int use_armor)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err = 0;
+ char *line;
+ /* Length is "EXPORT " + p + '\0'. */
+ int length = 7 + 1;
+ char *linep;
+
+ if (!gpgsm || reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (pattern && *pattern)
+ {
+ const char **pat = pattern;
+
+ while (*pat)
+ {
+ const char *patlet = *pat;
+
+ while (*patlet)
+ {
+ length++;
+ if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
+ length += 2;
+ patlet++;
+ }
+ pat++;
+ length++;
+ }
+ }
+ line = malloc (length);
+ if (!line)
+ return gpg_error_from_errno (errno);
+
+ strcpy (line, "EXPORT ");
+ linep = &line[7];
+
+ if (pattern && *pattern)
+ {
+ while (*pattern)
+ {
+ const char *patlet = *pattern;
+
+ while (*patlet)
+ {
+ switch (*patlet)
+ {
+ case '%':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '5';
+ break;
+ case ' ':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '0';
+ break;
+ case '+':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = 'B';
+ break;
+ default:
+ *(linep++) = *patlet;
+ break;
+ }
+ patlet++;
+ }
+ pattern++;
+ if (*pattern)
+ *linep++ = ' ';
+ }
+ }
+ *linep = '\0';
+
+ gpgsm->output_cb.data = keydata;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ use_armor ? "--armor" : 0);
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, line);
+ free (line);
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+
+ if (!gpgsm || !pubkey || seckey)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ gpgsm->input_cb.data = help_data;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ gpgsm->output_cb.data = pubkey;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ use_armor ? "--armor" : 0);
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, "GENKEY");
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_import (void *engine, gpgme_data_t keydata)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ gpgsm->input_cb.data = keydata;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, "IMPORT");
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_keylist (void *engine, const char *pattern, int secret_only,
+ gpgme_keylist_mode_t mode)
+{
+ engine_gpgsm_t gpgsm = engine;
+ char *line;
+ gpgme_error_t err;
+ int list_mode = 0;
+
+ if (mode & GPGME_KEYLIST_MODE_LOCAL)
+ list_mode |= 1;
+ if (mode & GPGME_KEYLIST_MODE_EXTERN)
+ list_mode |= 2;
+
+ if (!pattern)
+ pattern = "";
+
+ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
+ return gpg_error_from_errno (errno);
+ err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
+ free (line);
+ if (err)
+ return err;
+
+
+ /* Use the validation mode if required. We don't check for an error
+ yet because this is a pretty fresh gpgsm features. */
+ gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ (mode & GPGME_KEYLIST_MODE_VALIDATE)?
+ "OPTION with-validation=1":
+ "OPTION with-validation=0" ,
+ NULL, NULL);
+
+
+ /* Length is "LISTSECRETKEYS " + p + '\0'. */
+ line = malloc (15 + strlen (pattern) + 1);
+ if (!line)
+ return gpg_error_from_errno (errno);
+ if (secret_only)
+ {
+ strcpy (line, "LISTSECRETKEYS ");
+ strcpy (&line[15], pattern);
+ }
+ else
+ {
+ strcpy (line, "LISTKEYS ");
+ strcpy (&line[9], pattern);
+ }
+
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, line);
+ free (line);
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
+ int reserved, gpgme_keylist_mode_t mode)
+{
+ engine_gpgsm_t gpgsm = engine;
+ char *line;
+ gpgme_error_t err;
+ /* Length is "LISTSECRETKEYS " + p + '\0'. */
+ int length = 15 + 1;
+ char *linep;
+ int any_pattern = 0;
+ int list_mode = 0;
+
+ if (reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (mode & GPGME_KEYLIST_MODE_LOCAL)
+ list_mode |= 1;
+ if (mode & GPGME_KEYLIST_MODE_EXTERN)
+ list_mode |= 2;
+
+ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
+ return gpg_error_from_errno (errno);
+ err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
+ free (line);
+ if (err)
+ return err;
+
+ /* Use the validation mode if required. We don't check for an error
+ yet because this is a pretty fresh gpgsm features. */
+ gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
+ (mode & GPGME_KEYLIST_MODE_VALIDATE)?
+ "OPTION with-validation=1":
+ "OPTION with-validation=0" ,
+ NULL, NULL);
+
+
+ if (pattern && *pattern)
+ {
+ const char **pat = pattern;
+
+ while (*pat)
+ {
+ const char *patlet = *pat;
+
+ while (*patlet)
+ {
+ length++;
+ if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
+ length += 2;
+ patlet++;
+ }
+ pat++;
+ length++;
+ }
+ }
+ line = malloc (length);
+ if (!line)
+ return gpg_error_from_errno (errno);
+ if (secret_only)
+ {
+ strcpy (line, "LISTSECRETKEYS ");
+ linep = &line[15];
+ }
+ else
+ {
+ strcpy (line, "LISTKEYS ");
+ linep = &line[9];
+ }
+
+ if (pattern && *pattern)
+ {
+ while (*pattern)
+ {
+ const char *patlet = *pattern;
+
+ while (*patlet)
+ {
+ switch (*patlet)
+ {
+ case '%':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '5';
+ break;
+ case ' ':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = '0';
+ break;
+ case '+':
+ *(linep++) = '%';
+ *(linep++) = '2';
+ *(linep++) = 'B';
+ break;
+ default:
+ *(linep++) = *patlet;
+ break;
+ }
+ patlet++;
+ }
+ any_pattern = 1;
+ *linep++ = ' ';
+ pattern++;
+ }
+ }
+ if (any_pattern)
+ linep--;
+ *linep = '\0';
+
+ _gpgme_io_close (gpgsm->input_cb.fd);
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, line);
+ free (line);
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
+ gpgme_sig_mode_t mode, int use_armor, int use_textmode,
+ int include_certs, gpgme_ctx_t ctx /* FIXME */)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+ char *assuan_cmd;
+ int i;
+ gpgme_key_t key;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
+ return gpg_error_from_errno (errno);
+ err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd, NULL,NULL);
+ free (assuan_cmd);
+ if (err)
+ return err;
+
+ /* We must send a reset because we need to reset the list of
+ signers. Note that RESET does not reset OPTION commands. */
+ err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL);
+ if (err)
+ return err;
+
+ for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
+ {
+ const char *s = key->subkeys ? key->subkeys->fpr : NULL;
+ if (s && strlen (s) < 80)
+ {
+ char buf[100];
+
+ strcpy (stpcpy (buf, "SIGNER "), s);
+ err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
+ NULL, NULL);
+ }
+ else
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ gpgme_key_unref (key);
+ if (err)
+ return err;
+ }
+
+ gpgsm->input_cb.data = in;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ gpgsm->output_cb.data = out;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ use_armor ? "--armor" : 0);
+ if (err)
+ return err;
+ _gpgme_io_close (gpgsm->message_cb.fd);
+
+ err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
+ ? "SIGN --detached" : "SIGN");
+ return err;
+}
+
+
+static gpgme_error_t
+gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
+ gpgme_data_t plaintext)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgme_error_t err;
+
+ if (!gpgsm)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ gpgsm->input_cb.data = sig;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server,
+ map_input_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ if (plaintext)
+ {
+ /* Normal or cleartext signature. */
+ gpgsm->output_cb.data = plaintext;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "OUTPUT", gpgsm->output_fd_server,
+ 0);
+ _gpgme_io_close (gpgsm->message_cb.fd);
+ }
+ else
+ {
+ /* Detached signature. */
+ gpgsm->message_cb.data = signed_text;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE",
+ gpgsm->message_fd_server, 0);
+ _gpgme_io_close (gpgsm->output_cb.fd);
+ }
+
+ if (!err)
+ err = start (gpgsm, "VERIFY");
+
+ return err;
+}
+
+
+static void
+gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
+ void *fnc_value)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ gpgsm->status.fnc = fnc;
+ gpgsm->status.fnc_value = fnc_value;
+}
+
+
+static gpgme_error_t
+gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
+ void *fnc_value)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ gpgsm->colon.fnc = fnc;
+ gpgsm->colon.fnc_value = fnc_value;
+ gpgsm->colon.any = 0;
+ return 0;
+}
+
+
+static void
+gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
+{
+ engine_gpgsm_t gpgsm = engine;
+ gpgsm->io_cbs = *io_cbs;
+}
+
+
+static void
+gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
+{
+ engine_gpgsm_t gpgsm = engine;
+
+ if (gpgsm->io_cbs.event)
+ (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
+}
+
+
+struct engine_ops _gpgme_engine_ops_gpgsm =
+ {
+ /* Static functions. */
+ _gpgme_get_gpgsm_path,
+ gpgsm_get_version,
+ gpgsm_get_req_version,
+ gpgsm_new,
+
+ /* Member functions. */
+ gpgsm_release,
+ gpgsm_set_status_handler,
+ NULL, /* set_command_handler */
+ gpgsm_set_colon_line_handler,
+ gpgsm_decrypt,
+ gpgsm_delete,
+ NULL, /* edit */
+ gpgsm_encrypt,
+ NULL, /* encrypt_sign */
+ gpgsm_export,
+ gpgsm_export_ext,
+ gpgsm_genkey,
+ gpgsm_import,
+ gpgsm_keylist,
+ gpgsm_keylist_ext,
+ gpgsm_sign,
+ NULL, /* trustlist */
+ gpgsm_verify,
+ gpgsm_set_io_cbs,
+ gpgsm_io_event,
+ gpgsm_cancel
+ };
diff --git a/branches/gpgme-1-0-branch/gpgme/engine.c b/branches/gpgme-1-0-branch/gpgme/engine.c
new file mode 100644
index 00000000..6128c2f7
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/engine.c
@@ -0,0 +1,499 @@
+/* engine.c - GPGME engine support.
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "sema.h"
+#include "ops.h"
+
+#include "engine.h"
+#include "engine-backend.h"
+
+
+struct engine
+{
+ struct engine_ops *ops;
+ void *engine;
+};
+
+
+static struct engine_ops *engine_ops[] =
+ {
+ &_gpgme_engine_ops_gpg, /* OpenPGP. */
+#ifdef ENABLE_GPGSM
+ &_gpgme_engine_ops_gpgsm /* CMS. */
+#else
+ NULL
+#endif
+ };
+
+
+/* Get the file name of the engine for PROTOCOL. */
+static const char *
+engine_get_file_name (gpgme_protocol_t proto)
+{
+ if (proto > DIM (engine_ops))
+ return NULL;
+
+ if (engine_ops[proto] && engine_ops[proto]->get_file_name)
+ return (*engine_ops[proto]->get_file_name) ();
+ else
+ return NULL;
+}
+
+
+/* Get the version number of the engine for PROTOCOL. */
+static const char *
+engine_get_version (gpgme_protocol_t proto)
+{
+ if (proto > DIM (engine_ops))
+ return NULL;
+
+ if (engine_ops[proto] && engine_ops[proto]->get_version)
+ return (*engine_ops[proto]->get_version) ();
+ else
+ return NULL;
+}
+
+
+/* Get the required version number of the engine for PROTOCOL. */
+static const char *
+engine_get_req_version (gpgme_protocol_t proto)
+{
+ if (proto > DIM (engine_ops))
+ return NULL;
+
+ if (engine_ops[proto] && engine_ops[proto]->get_req_version)
+ return (*engine_ops[proto]->get_req_version) ();
+ else
+ return NULL;
+}
+
+
+/* Verify the version requirement for the engine for PROTOCOL. */
+gpgme_error_t
+gpgme_engine_check_version (gpgme_protocol_t proto)
+{
+ return _gpgme_compare_versions (engine_get_version (proto),
+ engine_get_req_version (proto))
+ ? 0 : gpg_error (GPG_ERR_INV_ENGINE);
+}
+
+
+/* Get the information about the configured and installed engines. A
+ pointer to the first engine in the statically allocated linked list
+ is returned in *INFO. If an error occurs, it is returned. */
+gpgme_error_t
+gpgme_get_engine_info (gpgme_engine_info_t *info)
+{
+ static gpgme_engine_info_t engine_info;
+ DEFINE_STATIC_LOCK (engine_info_lock);
+
+ LOCK (engine_info_lock);
+ if (!engine_info)
+ {
+ gpgme_engine_info_t *lastp = &engine_info;
+ gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
+ GPGME_PROTOCOL_CMS };
+ unsigned int proto;
+
+ for (proto = 0; proto < DIM (proto_list); proto++)
+ {
+ const char *file_name = engine_get_file_name (proto_list[proto]);
+
+ if (!file_name)
+ continue;
+
+ *lastp = malloc (sizeof (*engine_info));
+ if (!*lastp)
+ {
+ int saved_errno = errno;
+
+ while (engine_info)
+ {
+ gpgme_engine_info_t next_info = engine_info->next;
+ free (engine_info);
+ engine_info = next_info;
+ }
+ UNLOCK (engine_info_lock);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ (*lastp)->protocol = proto_list[proto];
+ (*lastp)->file_name = file_name;
+ (*lastp)->version = engine_get_version (proto_list[proto]);
+ (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
+ (*lastp)->next = NULL;
+ lastp = &(*lastp)->next;
+ }
+ }
+ UNLOCK (engine_info_lock);
+ *info = engine_info;
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_engine_new (gpgme_protocol_t proto, engine_t *r_engine,
+ const char *lc_ctype, const char *lc_messages)
+{
+ engine_t engine;
+
+ const char *file_name;
+ const char *version;
+
+ if (proto > DIM (engine_ops))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine_ops[proto])
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ file_name = engine_get_file_name (proto);
+ version = engine_get_version (proto);
+ if (!file_name || !version)
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ engine = calloc (1, sizeof *engine);
+ if (!engine)
+ return gpg_error_from_errno (errno);
+
+ engine->ops = engine_ops[proto];
+ if (engine_ops[proto]->new)
+ {
+ gpgme_error_t err = (*engine_ops[proto]->new) (&engine->engine,
+ lc_ctype,
+ lc_messages);
+ if (err)
+ {
+ free (engine);
+ return err;
+ }
+ }
+ else
+ engine->engine = NULL;
+
+ *r_engine = engine;
+ return 0;
+}
+
+
+void
+_gpgme_engine_release (engine_t engine)
+{
+ if (!engine)
+ return;
+
+ if (engine->ops->release)
+ (*engine->ops->release) (engine->engine);
+ free (engine);
+}
+
+
+void
+_gpgme_engine_set_status_handler (engine_t engine,
+ engine_status_handler_t fnc, void *fnc_value)
+{
+ if (!engine)
+ return;
+
+ if (engine->ops->set_status_handler)
+ (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
+}
+
+
+gpgme_error_t
+_gpgme_engine_set_command_handler (engine_t engine,
+ engine_command_handler_t fnc,
+ void *fnc_value,
+ gpgme_data_t linked_data)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->set_command_handler)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->set_command_handler) (engine->engine,
+ fnc, fnc_value, linked_data);
+}
+
+gpgme_error_t
+_gpgme_engine_set_colon_line_handler (engine_t engine,
+ engine_colon_line_handler_t fnc,
+ void *fnc_value)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->set_colon_line_handler)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->set_colon_line_handler) (engine->engine,
+ fnc, fnc_value);
+}
+
+gpgme_error_t
+_gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
+ gpgme_data_t plain)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->decrypt)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->decrypt) (engine->engine, ciph, plain);
+}
+
+gpgme_error_t
+_gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
+ int allow_secret)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->delete)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->delete) (engine->engine, key, allow_secret);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
+ gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->edit)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->encrypt)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
+ use_armor);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph,
+ int use_armor, gpgme_ctx_t ctx /* FIXME */)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->encrypt_sign)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
+ plain, ciph, use_armor, ctx);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_export (engine_t engine, const char *pattern,
+ unsigned int reserved, gpgme_data_t keydata,
+ int use_armor)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->export)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->export) (engine->engine, pattern, reserved,
+ keydata, use_armor);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
+ unsigned int reserved, gpgme_data_t keydata,
+ int use_armor)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->export_ext)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
+ keydata, use_armor);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
+ int use_armor, gpgme_data_t pubkey,
+ gpgme_data_t seckey)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->genkey)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
+ pubkey, seckey);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->import)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->import) (engine->engine, keydata);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_keylist (engine_t engine, const char *pattern,
+ int secret_only, gpgme_keylist_mode_t mode)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->keylist)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
+ int secret_only, int reserved,
+ gpgme_keylist_mode_t mode)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->keylist_ext)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
+ reserved, mode);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
+ gpgme_sig_mode_t mode, int use_armor,
+ int use_textmode, int include_certs,
+ gpgme_ctx_t ctx /* FIXME */)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->sign)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
+ use_textmode, include_certs, ctx);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->trustlist)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->trustlist) (engine->engine, pattern);
+}
+
+
+gpgme_error_t
+_gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
+ gpgme_data_t signed_text, gpgme_data_t plaintext)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->verify)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
+}
+
+
+void
+_gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
+{
+ if (!engine)
+ return;
+
+ (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
+}
+
+
+void
+_gpgme_engine_io_event (engine_t engine,
+ gpgme_event_io_t type, void *type_data)
+{
+ if (!engine)
+ return;
+
+ (*engine->ops->io_event) (engine->engine, type, type_data);
+}
+
+
+gpgme_error_t
+_gpgme_engine_cancel (engine_t engine)
+{
+ if (!engine)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!engine->ops->cancel)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ return (*engine->ops->cancel) (engine->engine);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/engine.h b/branches/gpgme-1-0-branch/gpgme/engine.h
new file mode 100644
index 00000000..42cec55c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/engine.h
@@ -0,0 +1,115 @@
+/* engine.h - GPGME engine interface.
+ 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 ENGINE_H
+#define ENGINE_H
+
+#include "gpgme.h"
+
+struct engine;
+typedef struct engine *engine_t;
+
+typedef gpgme_error_t (*engine_status_handler_t) (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+typedef gpgme_error_t (*engine_colon_line_handler_t) (void *priv, char *line);
+typedef gpgme_error_t (*engine_command_handler_t) (void *priv,
+ gpgme_status_code_t code,
+ const char *keyword,
+ int fd);
+
+gpgme_error_t _gpgme_engine_new (gpgme_protocol_t proto,
+ engine_t *r_engine,
+ const char *lc_ctype,
+ const char *lc_messages);
+void _gpgme_engine_release (engine_t engine);
+void _gpgme_engine_set_status_handler (engine_t engine,
+ engine_status_handler_t fnc,
+ void *fnc_value);
+gpgme_error_t _gpgme_engine_set_command_handler (engine_t engine,
+ engine_command_handler_t fnc,
+ void *fnc_value,
+ gpgme_data_t data);
+gpgme_error_t
+_gpgme_engine_set_colon_line_handler (engine_t engine,
+ engine_colon_line_handler_t fnc,
+ void *fnc_value);
+gpgme_error_t _gpgme_engine_op_decrypt (engine_t engine,
+ gpgme_data_t ciph,
+ gpgme_data_t plain);
+gpgme_error_t _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
+ int allow_secret);
+gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type,
+ gpgme_key_t key, gpgme_data_t out,
+ gpgme_ctx_t ctx /* FIXME */);
+gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine,
+ gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph,
+ int use_armor);
+gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
+ gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t ciph,
+ int use_armor,
+ gpgme_ctx_t ctx /* FIXME */);
+gpgme_error_t _gpgme_engine_op_export (engine_t engine, const char *pattern,
+ unsigned int reserved,
+ gpgme_data_t keydata, int use_armor);
+gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine,
+ const char *pattern[],
+ unsigned int reserved,
+ gpgme_data_t keydata,
+ int use_armor);
+gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
+ gpgme_data_t help_data,
+ int use_armor, gpgme_data_t pubkey,
+ gpgme_data_t seckey);
+gpgme_error_t _gpgme_engine_op_import (engine_t engine,
+ gpgme_data_t keydata);
+gpgme_error_t _gpgme_engine_op_keylist (engine_t engine,
+ const char *pattern,
+ int secret_only,
+ gpgme_keylist_mode_t mode);
+gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine,
+ const char *pattern[],
+ int secret_only,
+ int reserved,
+ gpgme_keylist_mode_t mode);
+gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in,
+ gpgme_data_t out, gpgme_sig_mode_t mode,
+ int use_armor, int use_textmode,
+ int include_certs,
+ gpgme_ctx_t ctx /* FIXME */);
+gpgme_error_t _gpgme_engine_op_trustlist (engine_t engine,
+ const char *pattern);
+gpgme_error_t _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
+ gpgme_data_t signed_text,
+ gpgme_data_t plaintext);
+
+void _gpgme_engine_set_io_cbs (engine_t engine,
+ gpgme_io_cbs_t io_cbs);
+void _gpgme_engine_io_event (engine_t engine,
+ gpgme_event_io_t type, void *type_data);
+
+gpgme_error_t _gpgme_engine_cancel (engine_t engine);
+
+#endif /* ENGINE_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/error.c b/branches/gpgme-1-0-branch/gpgme/error.c
new file mode 100644
index 00000000..b17bb093
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/error.c
@@ -0,0 +1,91 @@
+/* error.c - Error handling for GPGME.
+ Copyright (C) 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>
+
+/* Return a pointer to a string containing a description of the error
+ code in the error value ERR. */
+const char *
+gpgme_strerror (gpgme_error_t err)
+{
+ return gpg_strerror (err);
+}
+
+
+/* Return the error string for ERR in the user-supplied buffer BUF of
+ size BUFLEN. This function is, in contrast to gpg_strerror,
+ thread-safe if a thread-safe strerror_r() function is provided by
+ the system. If the function succeeds, 0 is returned and BUF
+ contains the string describing the error. If the buffer was not
+ large enough, ERANGE is returned and BUF contains as much of the
+ beginning of the error string as fits into the buffer. */
+int
+gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen)
+{
+ return gpg_strerror_r (err, buf, buflen);
+}
+
+
+/* Return a pointer to a string containing a description of the error
+ source in the error value ERR. */
+const char *
+gpgme_strsource (gpgme_error_t err)
+{
+ return gpg_strsource (err);
+}
+
+
+/* Retrieve the error code for the system error ERR. This returns
+ GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
+ this). */
+gpgme_err_code_t
+gpgme_err_code_from_errno (int err)
+{
+ return gpg_err_code_from_errno (err);
+}
+
+
+/* Retrieve the system error for the error code CODE. This returns 0
+ if CODE is not a system error code. */
+int
+gpgme_err_code_to_errno (gpgme_err_code_t code)
+{
+ return gpg_err_code_from_errno (code);
+}
+
+
+/* Return an error value with the error source SOURCE and the system
+ error ERR. */
+gpgme_error_t
+gpgme_err_make_from_errno (gpg_err_source_t source, int err)
+{
+ return gpg_err_make_from_errno (source, err);
+}
+
+
+/* Return an error value with the system error ERR. */
+gpgme_err_code_t
+gpgme_error_from_errno (int err)
+{
+ return gpgme_error (gpg_err_code_from_errno (err));
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/export.c b/branches/gpgme-1-0-branch/gpgme/export.c
new file mode 100644
index 00000000..59c68964
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/export.c
@@ -0,0 +1,116 @@
+/* export.c - Export a key.
+ 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 "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+static gpgme_error_t
+export_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ return 0;
+}
+
+
+static gpgme_error_t
+export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
+ unsigned int reserved, gpgme_data_t keydata)
+{
+ gpgme_error_t err;
+
+ if (!keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
+
+ return _gpgme_engine_op_export (ctx->engine, pattern, reserved, keydata,
+ ctx->use_armor);
+}
+
+
+/* Export the keys listed in RECP into KEYDATA. */
+gpgme_error_t
+gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
+ unsigned int reserved, gpgme_data_t keydata)
+{
+ return export_start (ctx, 0, pattern, reserved, keydata);
+}
+
+
+/* Export the keys listed in RECP into KEYDATA. */
+gpgme_error_t
+gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved,
+ gpgme_data_t keydata)
+{
+ gpgme_error_t err = export_start (ctx, 1, pattern, reserved, keydata);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+static gpgme_error_t
+export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
+ unsigned int reserved, gpgme_data_t keydata)
+{
+ gpgme_error_t err;
+
+ if (!keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
+
+ return _gpgme_engine_op_export_ext (ctx->engine, pattern, reserved, keydata,
+ ctx->use_armor);
+}
+
+
+/* Export the keys listed in RECP into KEYDATA. */
+gpgme_error_t
+gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[],
+ unsigned int reserved, gpgme_data_t keydata)
+{
+ return export_ext_start (ctx, 0, pattern, reserved, keydata);
+}
+
+
+/* Export the keys listed in RECP into KEYDATA. */
+gpgme_error_t
+gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
+ unsigned int reserved, gpgme_data_t keydata)
+{
+ gpgme_error_t err = export_ext_start (ctx, 1, pattern, reserved, keydata);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/funopen.c b/branches/gpgme-1-0-branch/gpgme/funopen.c
new file mode 100644
index 00000000..e768b057
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/funopen.c
@@ -0,0 +1,44 @@
+/* funopen.c - Replacement for funopen.
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_FOPENCOOKIE
+FILE *
+funopen(const void *cookie, cookie_read_function_t *readfn,
+ cookie_write_function_t *writefn,
+ cookie_seek_function_t *seekfn,
+ cookie_close_function_t *closefn)
+{
+ cookie_io_functions_t io = { read: readfn, write: writefn,
+ seek: seekfn,
+ close: closefn };
+
+ return fopencookie ((void *) cookie,
+ readfn ? ( writefn ? "rw" : "r" )
+ : ( writefn ? "w" : ""), io);
+}
+#else
+#error No known way to implement funopen.
+#endif
diff --git a/branches/gpgme-1-0-branch/gpgme/genkey.c b/branches/gpgme-1-0-branch/gpgme/genkey.c
new file mode 100644
index 00000000..229e7acb
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/genkey.c
@@ -0,0 +1,204 @@
+/* genkey.c - Key generation.
+ 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 <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_genkey_result result;
+
+ /* The key parameters passed to the crypto engine. */
+ gpgme_data_t key_parameter;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+
+ if (opd->result.fpr)
+ free (opd->result.fpr);
+ if (opd->key_parameter)
+ gpgme_data_release (opd->key_parameter);
+}
+
+
+gpgme_genkey_result_t
+gpgme_op_genkey_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+static gpgme_error_t
+genkey_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ /* Pipe the status code through the progress status handler. */
+ err = _gpgme_progress_status_handler (ctx, code, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_KEY_CREATED:
+ if (args && *args)
+ {
+ if (*args == 'B' || *args == 'P')
+ opd->result.primary = 1;
+ if (*args == 'B' || *args == 'S')
+ opd->result.sub = 1;
+ if (args[1] == ' ')
+ {
+ if (opd->result.fpr)
+ free (opd->result.fpr);
+ opd->result.fpr = strdup (&args[2]);
+ if (!opd->result.fpr)
+ return gpg_error_from_errno (errno);
+ }
+ }
+ break;
+
+ case GPGME_STATUS_EOF:
+ /* FIXME: Should return some more useful error value. */
+ if (!opd->result.primary && !opd->result.sub)
+ return gpg_error (GPG_ERR_GENERAL);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+get_key_parameter (const char *parms, gpgme_data_t *key_parameter)
+{
+ const char *content;
+ const char *attrib;
+ const char *endtag;
+
+ /* Extract the key parameter from the XML structure. */
+ parms = strstr (parms, "<GnupgKeyParms ");
+ if (!parms)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ content = strchr (parms, '>');
+ if (!content)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ content++;
+
+ attrib = strstr (parms, "format=\"internal\"");
+ if (!attrib || attrib >= content)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ endtag = strstr (content, "</GnupgKeyParms>");
+ /* FIXME: Check that there are no control statements inside. */
+ while (*content == '\n')
+ content++;
+
+ return gpgme_data_new_from_mem (key_parameter, content,
+ endtag - content, 1);
+}
+
+
+static gpgme_error_t
+genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ err = get_key_parameter (parms, &opd->key_parameter);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
+
+ return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
+ ctx->use_armor, pubkey, seckey);
+}
+
+
+/* Generate a new keypair and add it to the keyring. PUBKEY and
+ SECKEY should be null for now. PARMS specifies what keys should be
+ generated. */
+gpgme_error_t
+gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
+{
+ return genkey_start (ctx, 0, parms, pubkey, seckey);
+}
+
+
+/* Generate a new keypair and add it to the keyring. PUBKEY and
+ SECKEY should be null for now. PARMS specifies what keys should be
+ generated. */
+gpgme_error_t
+gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey,
+ gpgme_data_t seckey)
+{
+ gpgme_error_t err;
+
+ err = genkey_start (ctx, 1, parms, pubkey, seckey);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/get-env.c b/branches/gpgme-1-0-branch/gpgme/get-env.c
new file mode 100644
index 00000000..577498f4
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/get-env.c
@@ -0,0 +1,58 @@
+/* get_env.c - A getenv() replacement.
+ Copyright (C) 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 <errno.h>
+#include <string.h>
+
+#include "util.h"
+
+
+#if defined(HAVE_THREAD_SAFE_GETENV) || !defined (HAVE_GETENV_R)
+/* We prefer using getenv() if it is thread-safe. */
+
+/* Retrieve the environment variable NAME and return a copy of it in a
+ malloc()'ed buffer in *VALUE. If the environment variable is not
+ set, return NULL in *VALUE. */
+gpgme_error_t
+_gpgme_getenv (const char *name, char **value)
+{
+ char *env_value;
+
+ env_value = getenv (name);
+ if (!env_value)
+ *value = NULL;
+ else
+ {
+ *value = strdup (env_value);
+ if (!*value)
+ return gpg_error_from_errno (errno);
+ }
+ return 0;
+}
+
+#else
+
+/* FIXME: Implement this when we have the specification for it. */
+#error Use of getenv_r not implemented.
+
+#endif
diff --git a/branches/gpgme-1-0-branch/gpgme/gpgme-config.in b/branches/gpgme-1-0-branch/gpgme/gpgme-config.in
new file mode 100644
index 00000000..81e599d9
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/gpgme-config.in
@@ -0,0 +1,132 @@
+#!/bin/sh
+# Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+# Configure libgpg-error.
+gpg_error_cflags="@GPG_ERROR_CFLAGS@"
+gpg_error_libs="@GPG_ERROR_LIBS@"
+
+# Configure thread packages.
+thread_modules=""
+
+@HAVE_PTH_TRUE@thread_modules="$thread_modules pth"
+libs_pth="@PTH_LDFLAGS@ @PTH_LIBS@"
+cflags_pth="@PTH_CFLAGS@"
+
+@HAVE_PTHREAD_TRUE@thread_modules="$thread_modules pthread"
+libs_pthread="-lpthread"
+cflags_pthread=""
+
+output=""
+
+usage()
+{
+ cat <<EOF
+Usage: gpgme-config [OPTIONS]
+Options:
+ [--thread={${thread_modules}}]
+ [--prefix]
+ [--exec-prefix]
+ [--version]
+ [--api-version]
+ [--libs]
+ [--cflags]
+EOF
+ exit $1
+}
+
+if test $# -eq 0; then
+ usage 1 1>&2
+fi
+
+while test $# -gt 0; do
+ case "$1" in
+ -*=*)
+ optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'`
+ ;;
+ *)
+ optarg=
+ ;;
+ esac
+
+ case $1 in
+ --prefix=*)
+ # For compatibility reasons with old M4 macros, we ignore
+ # setting of prefix.
+ ;;
+ --prefix)
+ output="$output $prefix"
+ ;;
+ --exec-prefix=*)
+ ;;
+ --exec-prefix)
+ output="$output $exec_prefix"
+ ;;
+ --version)
+ echo "@VERSION@"
+ exit 0
+ ;;
+ --api-version)
+ echo "@GPGME_CONFIG_API_VERSION@"
+ exit 0
+ ;;
+ --cflags)
+ if test "x$includedir" != "x/usr/include" -a "x$includedir" != "x/include"; then
+ output="$output -I$includedir"
+ fi
+ case "$thread_module" in
+ pthread)
+ output="$output $cflags_pthread"
+ ;;
+ pth)
+ output="$output $cflags_pth"
+ ;;
+ esac
+ output="$output $gpg_error_cflags"
+ ;;
+ --libs)
+ if test "x$libdir" != "x/usr/lib" -a "x$libdir" != "x/lib"; then
+ output="$output -L$libdir"
+ fi
+ case "$thread_module" in
+ pthread)
+ output="$output -lgpgme-pthread $libs_pthread"
+ ;;
+ pth)
+ output="$output -lgpgme-pth $libs_pth"
+ ;;
+ *)
+ output="$output -lgpgme"
+ esac
+ output="$output $gpg_error_libs"
+ ;;
+ --thread=*)
+ for thread_mod in $thread_modules; do
+ if test "$thread_mod" = "$optarg"; then
+ thread_module="$optarg";
+ fi
+ done
+ if test "x$thread_module" = "x"; then
+ usage 1 1>&2
+ fi
+ ;;
+ *)
+ usage 1 1>&2
+ ;;
+ esac
+ shift
+done
+
+echo $output
diff --git a/branches/gpgme-1-0-branch/gpgme/gpgme.c b/branches/gpgme-1-0-branch/gpgme/gpgme.c
new file mode 100644
index 00000000..de707671
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/gpgme.c
@@ -0,0 +1,469 @@
+/* gpgme.c - GnuPG Made Easy.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <locale.h>
+
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+#include "wait.h"
+
+
+/* The default locale. */
+DEFINE_STATIC_LOCK (def_lc_lock);
+static char *def_lc_ctype;
+static char *def_lc_messages;
+
+
+/* Create a new context as an environment for GPGME crypto
+ operations. */
+gpgme_error_t
+gpgme_new (gpgme_ctx_t *r_ctx)
+{
+ gpgme_ctx_t ctx;
+
+ ctx = calloc (1, sizeof *ctx);
+ if (!ctx)
+ return gpg_error_from_errno (errno);
+ ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL;
+ ctx->include_certs = 1;
+ ctx->protocol = GPGME_PROTOCOL_OpenPGP;
+ _gpgme_fd_table_init (&ctx->fdt);
+
+ LOCK (def_lc_lock);
+ if (def_lc_ctype)
+ {
+ ctx->lc_ctype = strdup (def_lc_ctype);
+ if (!ctx->lc_ctype)
+ {
+ UNLOCK (def_lc_lock);
+ free (ctx);
+ return gpg_error_from_errno (errno);
+ }
+ }
+ else
+ def_lc_ctype = NULL;
+
+ if (def_lc_messages)
+ {
+ ctx->lc_messages = strdup (def_lc_messages);
+ if (!ctx->lc_messages)
+ {
+ UNLOCK (def_lc_lock);
+ if (ctx->lc_ctype)
+ free (ctx->lc_ctype);
+ free (ctx);
+ return gpg_error_from_errno (errno);
+ }
+ }
+ else
+ def_lc_messages = NULL;
+ UNLOCK (def_lc_lock);
+
+ *r_ctx = ctx;
+ return 0;
+}
+
+
+/* Cancel a pending asynchronous operation. */
+gpgme_error_t
+gpgme_cancel (gpgme_ctx_t ctx)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_engine_cancel (ctx->engine);
+ if (err)
+ return err;
+
+ err = gpg_error (GPG_ERR_CANCELED);
+ _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
+
+ return 0;
+}
+
+/* Release all resources associated with the given context. */
+void
+gpgme_release (gpgme_ctx_t ctx)
+{
+ _gpgme_engine_release (ctx->engine);
+ _gpgme_fd_table_deinit (&ctx->fdt);
+ _gpgme_release_result (ctx);
+ gpgme_signers_clear (ctx);
+ if (ctx->signers)
+ free (ctx->signers);
+ if (ctx->lc_ctype)
+ free (ctx->lc_ctype);
+ if (ctx->lc_messages)
+ free (ctx->lc_messages);
+ free (ctx);
+}
+
+
+void
+_gpgme_release_result (gpgme_ctx_t ctx)
+{
+ struct ctx_op_data *data = ctx->op_data;
+
+ while (data)
+ {
+ struct ctx_op_data *next_data = data->next;
+ if (data->cleanup)
+ (*data->cleanup) (data->hook);
+ free (data);
+ data = next_data;
+ }
+ ctx->op_data = NULL;
+}
+
+
+gpgme_error_t
+gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
+{
+ if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ ctx->protocol = protocol;
+ return 0;
+}
+
+
+gpgme_protocol_t
+gpgme_get_protocol (gpgme_ctx_t ctx)
+{
+ return ctx->protocol;
+}
+
+
+const char *
+gpgme_get_protocol_name (gpgme_protocol_t protocol)
+{
+ switch (protocol)
+ {
+ case GPGME_PROTOCOL_OpenPGP:
+ return "OpenPGP";
+
+ case GPGME_PROTOCOL_CMS:
+ return "CMS";
+
+ default:
+ return NULL;
+ }
+}
+
+/* Enable or disable the use of an ascii armor for all output. */
+void
+gpgme_set_armor (gpgme_ctx_t ctx, int yes)
+{
+ ctx->use_armor = yes;
+}
+
+
+/* Return the state of the armor flag. */
+int
+gpgme_get_armor (gpgme_ctx_t ctx)
+{
+ return ctx->use_armor;
+}
+
+
+/* Enable or disable the use of the special textmode. Textmode is for
+ example used for the RFC2015 signatures; note that the updated RFC
+ 3156 mandates that the MUA does some preparations so that textmode
+ is not needed anymore. */
+void
+gpgme_set_textmode (gpgme_ctx_t ctx, int yes)
+{
+ ctx->use_textmode = yes;
+}
+
+/* Return the state of the textmode flag. */
+int
+gpgme_get_textmode (gpgme_ctx_t ctx)
+{
+ return ctx->use_textmode;
+}
+
+
+/* Set the number of certifications to include in an S/MIME message.
+ The default is 1 (only the cert of the sender). -1 means all
+ certs, and -2 means all certs except the root cert. */
+void
+gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs)
+{
+ if (nr_of_certs < -2)
+ ctx->include_certs = -2;
+ else
+ ctx->include_certs = nr_of_certs;
+}
+
+
+/* Get the number of certifications to include in an S/MIME
+ message. */
+int
+gpgme_get_include_certs (gpgme_ctx_t ctx)
+{
+ return ctx->include_certs;
+}
+
+
+/* This function changes the default behaviour of the keylisting
+ functions. MODE is a bitwise-OR of the GPGME_KEYLIST_* flags. The
+ default mode is GPGME_KEYLIST_MODE_LOCAL. */
+gpgme_error_t
+gpgme_set_keylist_mode (gpgme_ctx_t ctx, gpgme_keylist_mode_t mode)
+{
+ if (!((mode & GPGME_KEYLIST_MODE_LOCAL)
+ || (mode & GPGME_KEYLIST_MODE_EXTERN)
+ || (mode & GPGME_KEYLIST_MODE_SIGS)))
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ ctx->keylist_mode = mode;
+ return 0;
+}
+
+/* This function returns the default behaviour of the keylisting
+ functions. */
+gpgme_keylist_mode_t
+gpgme_get_keylist_mode (gpgme_ctx_t ctx)
+{
+ return ctx->keylist_mode;
+}
+
+
+/* This function sets a callback function to be used to pass a
+ passphrase to gpg. */
+void
+gpgme_set_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb,
+ void *cb_value)
+{
+ ctx->passphrase_cb = cb;
+ ctx->passphrase_cb_value = cb_value;
+}
+
+
+/* This function returns the callback function to be used to pass a
+ passphrase to the crypto engine. */
+void
+gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *r_cb,
+ void **r_cb_value)
+{
+ if (r_cb)
+ *r_cb = ctx->passphrase_cb;
+ if (r_cb_value)
+ *r_cb_value = ctx->passphrase_cb_value;
+}
+
+
+/* This function sets a callback function to be used as a progress
+ indicator. */
+void
+gpgme_set_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t cb, void *cb_value)
+{
+ ctx->progress_cb = cb;
+ ctx->progress_cb_value = cb_value;
+}
+
+
+/* This function returns the callback function to be used as a
+ progress indicator. */
+void
+gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb,
+ void **r_cb_value)
+{
+ if (r_cb)
+ *r_cb = ctx->progress_cb;
+ if (r_cb_value)
+ *r_cb_value = ctx->progress_cb_value;
+}
+
+
+/* Set the I/O callback functions for CTX to IO_CBS. */
+void
+gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
+{
+ if (io_cbs)
+ ctx->io_cbs = *io_cbs;
+ else
+ {
+ ctx->io_cbs.add = NULL;
+ ctx->io_cbs.add_priv = NULL;
+ ctx->io_cbs.remove = NULL;
+ ctx->io_cbs.event = NULL;
+ ctx->io_cbs.event_priv = NULL;
+ }
+}
+
+
+/* This function returns the callback function for I/O. */
+void
+gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs)
+{
+ *io_cbs = ctx->io_cbs;
+}
+
+
+/* This function sets the locale for the context CTX, or the default
+ locale if CTX is a null pointer. */
+gpgme_error_t
+gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value)
+{
+ int failed = 0;
+ char *new_lc_ctype;
+ char *new_lc_messages;
+
+#define PREPARE_ONE_LOCALE(lcat, ucat) \
+ if (!failed && value \
+ && (category == LC_ALL || category == LC_ ## ucat)) \
+ { \
+ new_lc_ ## lcat = strdup (value); \
+ if (!new_lc_ ## lcat) \
+ failed = 1; \
+ } \
+ else \
+ new_lc_ ## lcat = NULL;
+
+ PREPARE_ONE_LOCALE (ctype, CTYPE);
+ PREPARE_ONE_LOCALE (messages, MESSAGES);
+
+ if (failed)
+ {
+ int saved_errno = errno;
+
+ if (new_lc_ctype)
+ free (new_lc_ctype);
+ if (new_lc_messages)
+ free (new_lc_messages);
+
+ return gpg_error_from_errno (saved_errno);
+ }
+
+#define SET_ONE_LOCALE(lcat, ucat) \
+ if (category == LC_ALL || category == LC_ ## ucat) \
+ { \
+ if (ctx) \
+ { \
+ if (ctx->lc_ ## lcat) \
+ free (ctx->lc_ ## lcat); \
+ ctx->lc_ ## lcat = new_lc_ ## lcat; \
+ } \
+ else \
+ { \
+ if (def_lc_ ## lcat) \
+ free (def_lc_ ## lcat); \
+ def_lc_ ## lcat = new_lc_ ## lcat; \
+ } \
+ }
+
+ if (!ctx)
+ LOCK (def_lc_lock);
+ SET_ONE_LOCALE (ctype, CTYPE);
+ SET_ONE_LOCALE (messages, MESSAGES);
+ if (!ctx)
+ UNLOCK (def_lc_lock);
+
+ return 0;
+}
+
+
+const char *
+gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo)
+{
+ switch (algo)
+ {
+ case GPGME_PK_RSA:
+ return "RSA";
+
+ case GPGME_PK_RSA_E:
+ return "RSA-E";
+
+ case GPGME_PK_RSA_S:
+ return "RSA-S";
+
+ case GPGME_PK_ELG_E:
+ return "ELG-E";
+
+ case GPGME_PK_DSA:
+ return "DSA";
+
+ case GPGME_PK_ELG:
+ return "ELG";
+
+ default:
+ return NULL;
+ }
+}
+
+
+const char *
+gpgme_hash_algo_name (gpgme_hash_algo_t algo)
+{
+ switch (algo)
+ {
+ case GPGME_MD_MD5:
+ return "MD5";
+
+ case GPGME_MD_SHA1:
+ return "SHA1";
+
+ case GPGME_MD_RMD160:
+ return "RIPEMD160";
+
+ case GPGME_MD_MD2:
+ return "MD2";
+
+ case GPGME_MD_TIGER:
+ return "TIGER192";
+
+ case GPGME_MD_HAVAL:
+ return "HAVAL";
+
+ case GPGME_MD_SHA256:
+ return "SHA256";
+
+ case GPGME_MD_SHA384:
+ return "SHA384";
+
+ case GPGME_MD_SHA512:
+ return "SHA512";
+
+ case GPGME_MD_MD4:
+ return "MD4";
+
+ case GPGME_MD_CRC32:
+ return "CRC32";
+
+ case GPGME_MD_CRC32_RFC1510:
+ return "CRC32RFC1510";
+
+ case GPGME_MD_CRC24_RFC2440:
+ return "CRC24RFC2440";
+
+ default:
+ return NULL;
+ }
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/gpgme.h b/branches/gpgme-1-0-branch/gpgme/gpgme.h
new file mode 100644
index 00000000..ffcfe0e9
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/gpgme.h
@@ -0,0 +1,1558 @@
+/* gpgme.h - Public interface to GnuPG Made Easy.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2002, 2003, 2004 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 GPGME_H
+#define GPGME_H
+
+#ifdef __GNUC__
+#define _GPGME_INLINE __inline__
+#elif __STDC_VERSION__ >= 199901L
+#define _GPGME_INLINE inline
+#else
+#define _GPGME_INLINE
+#endif
+
+/* Include stdio.h for the FILE type definition. */
+#include <stdio.h>
+
+#ifdef _MSC_VER
+ typedef long off_t;
+ typedef long ssize_t;
+#else
+# include <sys/types.h>
+#ifdef _WIN32
+typedef long ssize_t;
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#if 0 /* just to make Emacs auto-indent happy */
+}
+#endif
+#endif /* __cplusplus */
+
+#include <gpg-error.h>
+
+
+/* Check for compiler features. */
+#if __GNUC__
+#define _GPGME_GCC_VERSION (__GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__)
+
+#if _GPGME_GCC_VERSION > 30100
+#define _GPGME_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+#endif
+
+#ifndef _GPGME_DEPRECATED
+#define _GPGME_DEPRECATED
+#endif
+
+
+/* The version of this header should match the one of the library. Do
+ not use this symbol in your application, use gpgme_check_version
+ instead. The purpose of this macro is to let autoconf (using the
+ AM_PATH_GPGME macro) check that this header matches the installed
+ library. Warning: Do not edit the next line. configure will do
+ that for you! */
+#define GPGME_VERSION "1.0.1"
+
+
+/* Some opaque data types used by GPGME. */
+
+/* The context holds some global state and configration options, as
+ well as the results of a crypto operation. */
+struct gpgme_context;
+typedef struct gpgme_context *gpgme_ctx_t;
+
+/* The data object is used by GPGME to exchange arbitrary data. */
+struct gpgme_data;
+typedef struct gpgme_data *gpgme_data_t;
+
+
+/* Wrappers for the libgpg-error library. */
+
+typedef gpg_error_t gpgme_error_t;
+typedef gpg_err_code_t gpgme_err_code_t;
+typedef gpg_err_source_t gpgme_err_source_t;
+
+
+static _GPGME_INLINE gpgme_error_t
+gpgme_err_make (gpgme_err_source_t source, gpgme_err_code_t code)
+{
+ return gpg_err_make (source, code);
+}
+
+
+/* The user can define GPGME_ERR_SOURCE_DEFAULT before including this
+ file to specify a default source for gpgme_error. */
+#ifndef GPGME_ERR_SOURCE_DEFAULT
+#define GPGME_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1
+#endif
+
+static _GPGME_INLINE gpgme_error_t
+gpgme_error (gpgme_err_code_t code)
+{
+ return gpgme_err_make (GPGME_ERR_SOURCE_DEFAULT, code);
+}
+
+
+static _GPGME_INLINE gpgme_err_code_t
+gpgme_err_code (gpgme_error_t err)
+{
+ return gpg_err_code (err);
+}
+
+
+static _GPGME_INLINE gpgme_err_source_t
+gpgme_err_source (gpgme_error_t err)
+{
+ return gpg_err_source (err);
+}
+
+
+/* Return a pointer to a string containing a description of the error
+ code in the error value ERR. This function is not thread safe. */
+const char *gpgme_strerror (gpgme_error_t err);
+
+/* Return the error string for ERR in the user-supplied buffer BUF of
+ size BUFLEN. This function is, in contrast to gpg_strerror,
+ thread-safe if a thread-safe strerror_r() function is provided by
+ the system. If the function succeeds, 0 is returned and BUF
+ contains the string describing the error. If the buffer was not
+ large enough, ERANGE is returned and BUF contains as much of the
+ beginning of the error string as fits into the buffer. */
+int gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen);
+
+
+/* Return a pointer to a string containing a description of the error
+ source in the error value ERR. */
+const char *gpgme_strsource (gpgme_error_t err);
+
+
+/* Retrieve the error code for the system error ERR. This returns
+ GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
+ this). */
+gpgme_err_code_t gpgme_err_code_from_errno (int err);
+
+
+/* Retrieve the system error for the error code CODE. This returns 0
+ if CODE is not a system error code. */
+int gpgme_err_code_to_errno (gpgme_err_code_t code);
+
+
+/* Return an error value with the error source SOURCE and the system
+ error ERR. */
+gpgme_error_t gpgme_err_make_from_errno (gpgme_err_source_t source, int err);
+
+
+/* Return an error value with the system error ERR. */
+gpgme_err_code_t gpgme_error_from_errno (int err);
+
+
+/* The possible encoding mode of gpgme_data_t objects. */
+typedef enum
+ {
+ GPGME_DATA_ENCODING_NONE = 0, /* Not specified. */
+ GPGME_DATA_ENCODING_BINARY = 1,
+ GPGME_DATA_ENCODING_BASE64 = 2,
+ GPGME_DATA_ENCODING_ARMOR = 3 /* Either PEM or OpenPGP Armor. */
+ }
+gpgme_data_encoding_t;
+
+
+/* Public key algorithms from libgcrypt. */
+typedef enum
+ {
+ GPGME_PK_RSA = 1,
+ GPGME_PK_RSA_E = 2,
+ GPGME_PK_RSA_S = 3,
+ GPGME_PK_ELG_E = 16,
+ GPGME_PK_DSA = 17,
+ GPGME_PK_ELG = 20
+ }
+gpgme_pubkey_algo_t;
+
+
+/* Hash algorithms from libgcrypt. */
+typedef enum
+ {
+ GPGME_MD_NONE = 0,
+ GPGME_MD_MD5 = 1,
+ GPGME_MD_SHA1 = 2,
+ GPGME_MD_RMD160 = 3,
+ GPGME_MD_MD2 = 5,
+ GPGME_MD_TIGER = 6, /* TIGER/192. */
+ GPGME_MD_HAVAL = 7, /* HAVAL, 5 pass, 160 bit. */
+ GPGME_MD_SHA256 = 8,
+ GPGME_MD_SHA384 = 9,
+ GPGME_MD_SHA512 = 10,
+ GPGME_MD_MD4 = 301,
+ GPGME_MD_CRC32 = 302,
+ GPGME_MD_CRC32_RFC1510 = 303,
+ GPGME_MD_CRC24_RFC2440 = 304
+ }
+gpgme_hash_algo_t;
+
+
+/* The possible signature stati. Deprecated, use error value in sig
+ status. */
+typedef enum
+ {
+ GPGME_SIG_STAT_NONE = 0,
+ GPGME_SIG_STAT_GOOD = 1,
+ GPGME_SIG_STAT_BAD = 2,
+ GPGME_SIG_STAT_NOKEY = 3,
+ GPGME_SIG_STAT_NOSIG = 4,
+ GPGME_SIG_STAT_ERROR = 5,
+ GPGME_SIG_STAT_DIFF = 6,
+ GPGME_SIG_STAT_GOOD_EXP = 7,
+ GPGME_SIG_STAT_GOOD_EXPKEY = 8
+ }
+_gpgme_sig_stat_t;
+typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED;
+
+
+/* The available signature modes. */
+typedef enum
+ {
+ GPGME_SIG_MODE_NORMAL = 0,
+ GPGME_SIG_MODE_DETACH = 1,
+ GPGME_SIG_MODE_CLEAR = 2
+ }
+gpgme_sig_mode_t;
+
+
+/* The available key and signature attributes. Deprecated, use the
+ individual result structures instead. */
+typedef enum
+ {
+ GPGME_ATTR_KEYID = 1,
+ GPGME_ATTR_FPR = 2,
+ GPGME_ATTR_ALGO = 3,
+ GPGME_ATTR_LEN = 4,
+ GPGME_ATTR_CREATED = 5,
+ GPGME_ATTR_EXPIRE = 6,
+ GPGME_ATTR_OTRUST = 7,
+ GPGME_ATTR_USERID = 8,
+ GPGME_ATTR_NAME = 9,
+ GPGME_ATTR_EMAIL = 10,
+ GPGME_ATTR_COMMENT = 11,
+ GPGME_ATTR_VALIDITY = 12,
+ GPGME_ATTR_LEVEL = 13,
+ GPGME_ATTR_TYPE = 14,
+ GPGME_ATTR_IS_SECRET = 15,
+ GPGME_ATTR_KEY_REVOKED = 16,
+ GPGME_ATTR_KEY_INVALID = 17,
+ GPGME_ATTR_UID_REVOKED = 18,
+ GPGME_ATTR_UID_INVALID = 19,
+ GPGME_ATTR_KEY_CAPS = 20,
+ GPGME_ATTR_CAN_ENCRYPT = 21,
+ GPGME_ATTR_CAN_SIGN = 22,
+ GPGME_ATTR_CAN_CERTIFY = 23,
+ GPGME_ATTR_KEY_EXPIRED = 24,
+ GPGME_ATTR_KEY_DISABLED = 25,
+ GPGME_ATTR_SERIAL = 26,
+ GPGME_ATTR_ISSUER = 27,
+ GPGME_ATTR_CHAINID = 28,
+ GPGME_ATTR_SIG_STATUS = 29,
+ GPGME_ATTR_ERRTOK = 30,
+ GPGME_ATTR_SIG_SUMMARY = 31,
+ GPGME_ATTR_SIG_CLASS = 32
+ }
+_gpgme_attr_t;
+typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED;
+
+
+/* The available validities for a trust item or key. */
+typedef enum
+ {
+ GPGME_VALIDITY_UNKNOWN = 0,
+ GPGME_VALIDITY_UNDEFINED = 1,
+ GPGME_VALIDITY_NEVER = 2,
+ GPGME_VALIDITY_MARGINAL = 3,
+ GPGME_VALIDITY_FULL = 4,
+ GPGME_VALIDITY_ULTIMATE = 5
+ }
+gpgme_validity_t;
+
+
+/* The available protocols. */
+typedef enum
+ {
+ GPGME_PROTOCOL_OpenPGP = 0, /* The default mode. */
+ GPGME_PROTOCOL_CMS = 1
+ }
+gpgme_protocol_t;
+
+
+/* The available keylist mode flags. */
+#define GPGME_KEYLIST_MODE_LOCAL 1
+#define GPGME_KEYLIST_MODE_EXTERN 2
+#define GPGME_KEYLIST_MODE_SIGS 4
+#define GPGME_KEYLIST_MODE_VALIDATE 256
+
+typedef unsigned int gpgme_keylist_mode_t;
+
+
+/* The possible stati for the edit operation. */
+typedef enum
+ {
+ GPGME_STATUS_EOF,
+ /* mkstatus processing starts here */
+ GPGME_STATUS_ENTER,
+ GPGME_STATUS_LEAVE,
+ GPGME_STATUS_ABORT,
+
+ GPGME_STATUS_GOODSIG,
+ GPGME_STATUS_BADSIG,
+ GPGME_STATUS_ERRSIG,
+
+ GPGME_STATUS_BADARMOR,
+
+ GPGME_STATUS_RSA_OR_IDEA,
+ GPGME_STATUS_KEYEXPIRED,
+ GPGME_STATUS_KEYREVOKED,
+
+ GPGME_STATUS_TRUST_UNDEFINED,
+ GPGME_STATUS_TRUST_NEVER,
+ GPGME_STATUS_TRUST_MARGINAL,
+ GPGME_STATUS_TRUST_FULLY,
+ GPGME_STATUS_TRUST_ULTIMATE,
+
+ GPGME_STATUS_SHM_INFO,
+ GPGME_STATUS_SHM_GET,
+ GPGME_STATUS_SHM_GET_BOOL,
+ GPGME_STATUS_SHM_GET_HIDDEN,
+
+ GPGME_STATUS_NEED_PASSPHRASE,
+ GPGME_STATUS_VALIDSIG,
+ GPGME_STATUS_SIG_ID,
+ GPGME_STATUS_ENC_TO,
+ GPGME_STATUS_NODATA,
+ GPGME_STATUS_BAD_PASSPHRASE,
+ GPGME_STATUS_NO_PUBKEY,
+ GPGME_STATUS_NO_SECKEY,
+ GPGME_STATUS_NEED_PASSPHRASE_SYM,
+ GPGME_STATUS_DECRYPTION_FAILED,
+ GPGME_STATUS_DECRYPTION_OKAY,
+ GPGME_STATUS_MISSING_PASSPHRASE,
+ GPGME_STATUS_GOOD_PASSPHRASE,
+ GPGME_STATUS_GOODMDC,
+ GPGME_STATUS_BADMDC,
+ GPGME_STATUS_ERRMDC,
+ GPGME_STATUS_IMPORTED,
+ GPGME_STATUS_IMPORT_OK,
+ GPGME_STATUS_IMPORT_PROBLEM,
+ GPGME_STATUS_IMPORT_RES,
+ GPGME_STATUS_FILE_START,
+ GPGME_STATUS_FILE_DONE,
+ GPGME_STATUS_FILE_ERROR,
+
+ GPGME_STATUS_BEGIN_DECRYPTION,
+ GPGME_STATUS_END_DECRYPTION,
+ GPGME_STATUS_BEGIN_ENCRYPTION,
+ GPGME_STATUS_END_ENCRYPTION,
+
+ GPGME_STATUS_DELETE_PROBLEM,
+ GPGME_STATUS_GET_BOOL,
+ GPGME_STATUS_GET_LINE,
+ GPGME_STATUS_GET_HIDDEN,
+ GPGME_STATUS_GOT_IT,
+ GPGME_STATUS_PROGRESS,
+ GPGME_STATUS_SIG_CREATED,
+ GPGME_STATUS_SESSION_KEY,
+ GPGME_STATUS_NOTATION_NAME,
+ GPGME_STATUS_NOTATION_DATA,
+ GPGME_STATUS_POLICY_URL,
+ GPGME_STATUS_BEGIN_STREAM,
+ GPGME_STATUS_END_STREAM,
+ GPGME_STATUS_KEY_CREATED,
+ GPGME_STATUS_USERID_HINT,
+ GPGME_STATUS_UNEXPECTED,
+ GPGME_STATUS_INV_RECP,
+ GPGME_STATUS_NO_RECP,
+ GPGME_STATUS_ALREADY_SIGNED,
+ GPGME_STATUS_SIGEXPIRED,
+ GPGME_STATUS_EXPSIG,
+ GPGME_STATUS_EXPKEYSIG,
+ GPGME_STATUS_TRUNCATED,
+ GPGME_STATUS_ERROR,
+ GPGME_STATUS_NEWSIG,
+ GPGME_STATUS_REVKEYSIG
+ }
+gpgme_status_code_t;
+
+
+/* The engine information structure. */
+struct _gpgme_engine_info
+{
+ struct _gpgme_engine_info *next;
+
+ /* The protocol ID. */
+ gpgme_protocol_t protocol;
+
+ /* The file name of the engine binary. */
+ const char *file_name;
+
+ /* The version string of the installed engine. */
+ const char *version;
+
+ /* The minimum version required for GPGME. */
+ const char *req_version;
+};
+typedef struct _gpgme_engine_info *gpgme_engine_info_t;
+
+
+/* A subkey from a key. */
+struct _gpgme_subkey
+{
+ struct _gpgme_subkey *next;
+
+ /* True if subkey is revoked. */
+ unsigned int revoked : 1;
+
+ /* True if subkey is expired. */
+ unsigned int expired : 1;
+
+ /* True if subkey is disabled. */
+ unsigned int disabled : 1;
+
+ /* True if subkey is invalid. */
+ unsigned int invalid : 1;
+
+ /* True if subkey can be used for encryption. */
+ unsigned int can_encrypt : 1;
+
+ /* True if subkey can be used for signing. */
+ unsigned int can_sign : 1;
+
+ /* True if subkey can be used for certification. */
+ unsigned int can_certify : 1;
+
+ /* True if subkey is secret. */
+ unsigned int secret : 1;
+
+ /* True if subkey can be used for authentication. */
+ unsigned int can_authenticate : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 23;
+
+ /* Public key algorithm supported by this subkey. */
+ gpgme_pubkey_algo_t pubkey_algo;
+
+ /* Length of the subkey. */
+ unsigned int length;
+
+ /* The key ID of the subkey. */
+ char *keyid;
+
+ /* Internal to GPGME, do not use. */
+ char _keyid[16 + 1];
+
+ /* The fingerprint of the subkey in hex digit form. */
+ char *fpr;
+
+ /* The creation timestamp, -1 if invalid, 0 if not available. */
+ long int timestamp;
+
+ /* The expiration timestamp, 0 if the subkey does not expire. */
+ long int expires;
+};
+typedef struct _gpgme_subkey *gpgme_subkey_t;
+
+
+/* A signature on a user ID. */
+struct _gpgme_key_sig
+{
+ struct _gpgme_key_sig *next;
+
+ /* True if the signature is a revocation signature. */
+ unsigned int revoked : 1;
+
+ /* True if the signature is expired. */
+ unsigned int expired : 1;
+
+ /* True if the signature is invalid. */
+ unsigned int invalid : 1;
+
+ /* True if the signature should be exported. */
+ unsigned int exportable : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 28;
+
+ /* The public key algorithm used to create the signature. */
+ gpgme_pubkey_algo_t pubkey_algo;
+
+ /* The key ID of key used to create the signature. */
+ char *keyid;
+
+ /* Internal to GPGME, do not use. */
+ char _keyid[16 + 1];
+
+ /* The creation timestamp, -1 if invalid, 0 if not available. */
+ long int timestamp;
+
+ /* The expiration timestamp, 0 if the subkey does not expire. */
+ long int expires;
+
+ /* Same as in gpgme_signature_t. */
+ gpgme_error_t status;
+
+#ifdef __cplusplus
+ unsigned int _obsolete_class _GPGME_DEPRECATED;
+#else
+ /* Must be set to SIG_CLASS below. */
+ unsigned int class _GPGME_DEPRECATED;
+#endif
+
+ /* The user ID string. */
+ char *uid;
+
+ /* The name part of the user ID. */
+ char *name;
+
+ /* The email part of the user ID. */
+ char *email;
+
+ /* The comment part of the user ID. */
+ char *comment;
+
+ /* Crypto backend specific signature class. */
+ unsigned int sig_class;
+};
+typedef struct _gpgme_key_sig *gpgme_key_sig_t;
+
+
+/* An user ID from a key. */
+struct _gpgme_user_id
+{
+ struct _gpgme_user_id *next;
+
+ /* True if the user ID is revoked. */
+ unsigned int revoked : 1;
+
+ /* True if the user ID is invalid. */
+ unsigned int invalid : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 30;
+
+ /* The validity of the user ID. */
+ gpgme_validity_t validity;
+
+ /* The user ID string. */
+ char *uid;
+
+ /* The name part of the user ID. */
+ char *name;
+
+ /* The email part of the user ID. */
+ char *email;
+
+ /* The comment part of the user ID. */
+ char *comment;
+
+ /* The signatures of the user ID. */
+ gpgme_key_sig_t signatures;
+
+ /* Internal to GPGME, do not use. */
+ gpgme_key_sig_t _last_keysig;
+};
+typedef struct _gpgme_user_id *gpgme_user_id_t;
+
+
+/* A key from the keyring. */
+struct _gpgme_key
+{
+ /* Internal to GPGME, do not use. */
+ unsigned int _refs;
+
+ /* True if key is revoked. */
+ unsigned int revoked : 1;
+
+ /* True if key is expired. */
+ unsigned int expired : 1;
+
+ /* True if key is disabled. */
+ unsigned int disabled : 1;
+
+ /* True if key is invalid. */
+ unsigned int invalid : 1;
+
+ /* True if key can be used for encryption. */
+ unsigned int can_encrypt : 1;
+
+ /* True if key can be used for signing. */
+ unsigned int can_sign : 1;
+
+ /* True if key can be used for certification. */
+ unsigned int can_certify : 1;
+
+ /* True if key is secret. */
+ unsigned int secret : 1;
+
+ /* True if key can be used for authentication. */
+ unsigned int can_authenticate : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 23;
+
+ /* This is the protocol supported by this key. */
+ gpgme_protocol_t protocol;
+
+ /* If protocol is GPGME_PROTOCOL_CMS, this string contains the
+ issuer serial. */
+ char *issuer_serial;
+
+ /* If protocol is GPGME_PROTOCOL_CMS, this string contains the
+ issuer name. */
+ char *issuer_name;
+
+ /* If protocol is GPGME_PROTOCOL_CMS, this string contains the chain
+ ID. */
+ char *chain_id;
+
+ /* If protocol is GPGME_PROTOCOL_OpenPGP, this field contains the
+ owner trust. */
+ gpgme_validity_t owner_trust;
+
+ /* The subkeys of the key. */
+ gpgme_subkey_t subkeys;
+
+ /* The user IDs of the key. */
+ gpgme_user_id_t uids;
+
+ /* Internal to GPGME, do not use. */
+ gpgme_subkey_t _last_subkey;
+
+ /* Internal to GPGME, do not use. */
+ gpgme_user_id_t _last_uid;
+
+ /* The keylist mode that was active when listing the key. */
+ gpgme_keylist_mode_t keylist_mode;
+};
+typedef struct _gpgme_key *gpgme_key_t;
+
+
+
+/* Types for callback functions. */
+
+/* Request a passphrase from the user. */
+typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook,
+ const char *uid_hint,
+ const char *passphrase_info,
+ int prev_was_bad, int fd);
+
+/* Inform the user about progress made. */
+typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what,
+ int type, int current, int total);
+
+/* Interact with the user about an edit operation. */
+typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque,
+ gpgme_status_code_t status,
+ const char *args, int fd);
+
+
+/* Context management functions. */
+
+/* Create a new context and return it in CTX. */
+gpgme_error_t gpgme_new (gpgme_ctx_t *ctx);
+
+/* Release the context CTX. */
+void gpgme_release (gpgme_ctx_t ctx);
+
+/* Set the protocol to be used by CTX to PROTO. */
+gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto);
+
+/* Get the protocol used with CTX */
+gpgme_protocol_t gpgme_get_protocol (gpgme_ctx_t ctx);
+
+/* Get the string describing protocol PROTO, or NULL if invalid. */
+const char *gpgme_get_protocol_name (gpgme_protocol_t proto);
+
+/* If YES is non-zero, enable armor mode in CTX, disable it otherwise. */
+void gpgme_set_armor (gpgme_ctx_t ctx, int yes);
+
+/* Return non-zero if armor mode is set in CTX. */
+int gpgme_get_armor (gpgme_ctx_t ctx);
+
+/* If YES is non-zero, enable text mode in CTX, disable it otherwise. */
+void gpgme_set_textmode (gpgme_ctx_t ctx, int yes);
+
+/* Return non-zero if text mode is set in CTX. */
+int gpgme_get_textmode (gpgme_ctx_t ctx);
+
+/* Include up to NR_OF_CERTS certificates in an S/MIME message. */
+void gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs);
+
+/* Return the number of certs to include in an S/MIME message. */
+int gpgme_get_include_certs (gpgme_ctx_t ctx);
+
+/* Set keylist mode in CTX to MODE. */
+gpgme_error_t gpgme_set_keylist_mode (gpgme_ctx_t ctx,
+ gpgme_keylist_mode_t mode);
+
+/* Get keylist mode in CTX. */
+gpgme_keylist_mode_t gpgme_get_keylist_mode (gpgme_ctx_t ctx);
+
+/* Set the passphrase callback function in CTX to CB. HOOK_VALUE is
+ passed as first argument to the passphrase callback function. */
+void gpgme_set_passphrase_cb (gpgme_ctx_t ctx,
+ gpgme_passphrase_cb_t cb, void *hook_value);
+
+/* Get the current passphrase callback function in *CB and the current
+ hook value in *HOOK_VALUE. */
+void gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *cb,
+ void **hook_value);
+
+/* Set the progress callback function in CTX to CB. HOOK_VALUE is
+ passed as first argument to the progress callback function. */
+void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb,
+ void *hook_value);
+
+/* Get the current progress callback function in *CB and the current
+ hook value in *HOOK_VALUE. */
+void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb,
+ void **hook_value);
+
+/* This function sets the locale for the context CTX, or the default
+ locale if CTX is a null pointer. */
+gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category,
+ const char *value);
+
+/* Return a statically allocated string with the name of the public
+ key algorithm ALGO, or NULL if that name is not known. */
+const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo);
+
+/* Return a statically allocated string with the name of the hash
+ algorithm ALGO, or NULL if that name is not known. */
+const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo);
+
+
+/* Delete all signers from CTX. */
+void gpgme_signers_clear (gpgme_ctx_t ctx);
+
+/* Add KEY to list of signers in CTX. */
+gpgme_error_t gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key);
+
+/* Return the SEQth signer's key in CTX. */
+gpgme_key_t gpgme_signers_enum (const gpgme_ctx_t ctx, int seq);
+
+/* Retrieve the signature status of signature IDX in CTX after a
+ successful verify operation in R_STAT (if non-null). The creation
+ time stamp of the signature is returned in R_CREATED (if non-null).
+ The function returns a string containing the fingerprint.
+ Deprecated, use verify result directly. */
+const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
+ _gpgme_sig_stat_t *r_stat,
+ time_t *r_created) _GPGME_DEPRECATED;
+
+/* Retrieve certain attributes of a signature. IDX is the index
+ number of the signature after a successful verify operation. WHAT
+ is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
+ one. WHATIDX is to be passed as 0 for most attributes . */
+unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t c, int idx,
+ _gpgme_attr_t what, int whatidx)
+ _GPGME_DEPRECATED;
+const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx,
+ _gpgme_attr_t what, int whatidx)
+ _GPGME_DEPRECATED;
+
+
+/* Get the key used to create signature IDX in CTX and return it in
+ R_KEY. */
+gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
+ _GPGME_DEPRECATED;
+
+
+/* Run control. */
+
+/* The type of an I/O callback function. */
+typedef gpgme_error_t (*gpgme_io_cb_t) (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,
+ 1: for reading). FNC_DATA should be passed as DATA to FNC. The
+ function should return a TAG suitable for the corresponding
+ gpgme_remove_io_cb_t, and an error value. */
+typedef gpgme_error_t (*gpgme_register_io_cb_t) (void *data, int fd, int dir,
+ gpgme_io_cb_t fnc,
+ void *fnc_data, void **tag);
+
+/* The type of a function that can remove a previously registered I/O
+ callback function given TAG as returned by the register
+ function. */
+typedef void (*gpgme_remove_io_cb_t) (void *tag);
+
+typedef enum
+ {
+ GPGME_EVENT_START,
+ GPGME_EVENT_DONE,
+ GPGME_EVENT_NEXT_KEY,
+ GPGME_EVENT_NEXT_TRUSTITEM
+ }
+gpgme_event_io_t;
+
+/* The type of a function that is called when a context finished an
+ operation. */
+typedef void (*gpgme_event_io_cb_t) (void *data, gpgme_event_io_t type,
+ void *type_data);
+
+struct gpgme_io_cbs
+{
+ gpgme_register_io_cb_t add;
+ void *add_priv;
+ gpgme_remove_io_cb_t remove;
+ gpgme_event_io_cb_t event;
+ void *event_priv;
+};
+typedef struct gpgme_io_cbs *gpgme_io_cbs_t;
+
+/* Set the I/O callback functions in CTX to IO_CBS. */
+void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
+
+/* Get the current I/O callback functions. */
+void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs);
+
+/* Process the pending operation and, if HANG is non-zero, wait for
+ the pending operation to finish. */
+gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang);
+
+
+/* Functions to handle data objects. */
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle HANDLE. Return the number of characters read, 0 on EOF
+ and -1 on error. If an error occurs, errno is set. */
+typedef ssize_t (*gpgme_data_read_cb_t) (void *handle, void *buffer,
+ size_t size);
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle HANDLE. Return the number of characters written, or -1
+ on error. If an error occurs, errno is set. */
+typedef ssize_t (*gpgme_data_write_cb_t) (void *handle, const void *buffer,
+ size_t size);
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle HANDLE to OFFSET, relativ to
+ WHENCE. */
+typedef off_t (*gpgme_data_seek_cb_t) (void *handle, off_t offset, int whence);
+
+/* Close the data object with the handle DL. */
+typedef void (*gpgme_data_release_cb_t) (void *handle);
+
+struct gpgme_data_cbs
+{
+ gpgme_data_read_cb_t read;
+ gpgme_data_write_cb_t write;
+ gpgme_data_seek_cb_t seek;
+ gpgme_data_release_cb_t release;
+};
+typedef struct gpgme_data_cbs *gpgme_data_cbs_t;
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle DH. Return the number of characters read, 0 on EOF and
+ -1 on error. If an error occurs, errno is set. */
+ssize_t gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size);
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle DH. Return the number of characters written, or -1 on
+ error. If an error occurs, errno is set. */
+ssize_t gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size);
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle DH to OFFSET, relativ to
+ WHENCE. */
+off_t gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence);
+
+/* Create a new data buffer and return it in R_DH. */
+gpgme_error_t gpgme_data_new (gpgme_data_t *r_dh);
+
+/* Destroy the data buffer DH. */
+void gpgme_data_release (gpgme_data_t dh);
+
+/* Create a new data buffer filled with SIZE bytes starting from
+ BUFFER. If COPY is zero, copying is delayed until necessary, and
+ the data is taken from the original location when needed. */
+gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh,
+ const char *buffer, size_t size,
+ int copy);
+
+/* Destroy the data buffer DH and return a pointer to its content.
+ The memory has be to released with free by the user. It's size is
+ returned in R_LEN. */
+char *gpgme_data_release_and_get_mem (gpgme_data_t dh, size_t *r_len);
+
+gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh,
+ gpgme_data_cbs_t cbs,
+ void *handle);
+
+gpgme_error_t gpgme_data_new_from_fd (gpgme_data_t *dh, int fd);
+
+gpgme_error_t gpgme_data_new_from_stream (gpgme_data_t *dh, FILE *stream);
+
+/* Return the encoding attribute of the data buffer DH */
+gpgme_data_encoding_t gpgme_data_get_encoding (gpgme_data_t dh);
+
+/* Set the encoding attribute of data buffer DH to ENC */
+gpgme_error_t gpgme_data_set_encoding (gpgme_data_t dh,
+ gpgme_data_encoding_t enc);
+
+
+
+/* Create a new data buffer which retrieves the data from the callback
+ function READ_CB. Deprecated, please use gpgme_data_new_from_cbs
+ instead. */
+gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh,
+ int (*read_cb) (void*,char *,
+ size_t,size_t*),
+ void *read_cb_value)
+ _GPGME_DEPRECATED;
+
+/* Create a new data buffer filled with the content of file FNAME.
+ COPY must be non-zero. For delayed read, please use
+ gpgme_data_new_from_fd or gpgme_data_new_from stream instead. */
+gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh,
+ const char *fname,
+ int copy);
+
+/* Create a new data buffer filled with LENGTH bytes starting from
+ OFFSET within the file FNAME or stream FP (exactly one must be
+ non-zero). */
+gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh,
+ const char *fname, FILE *fp,
+ off_t offset, size_t length);
+
+/* Reset the read pointer in DH. Deprecated, please use
+ gpgme_data_seek instead. */
+gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED;
+
+
+/* Key and trust functions. */
+
+/* Get the key with the fingerprint FPR from the crypto backend. If
+ SECRET is true, get the secret key. */
+gpgme_error_t gpgme_get_key (gpgme_ctx_t ctx, const char *fpr,
+ gpgme_key_t *r_key, int secret);
+
+/* Acquire a reference to KEY. */
+void gpgme_key_ref (gpgme_key_t key);
+
+/* Release a reference to KEY. If this was the last one the key is
+ destroyed. */
+void gpgme_key_unref (gpgme_key_t key);
+void gpgme_key_release (gpgme_key_t key);
+
+/* Return the value of the attribute WHAT of KEY, which has to be
+ representable by a string. IDX specifies the sub key or user ID
+ for attributes related to sub keys or user IDs. Deprecated, use
+ key structure directly instead. */
+const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+/* Return the value of the attribute WHAT of KEY, which has to be
+ representable by an unsigned integer. IDX specifies the sub key or
+ user ID for attributes related to sub keys or user IDs.
+ Deprecated, use key structure directly instead. */
+unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+/* Return the value of the attribute WHAT of a signature on user ID
+ UID_IDX in KEY, which has to be representable by a string. IDX
+ specifies the signature. Deprecated, use key structure directly
+ instead. */
+const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
+ _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+/* Return the value of the attribute WHAT of a signature on user ID
+ UID_IDX in KEY, which has to be representable by an unsigned
+ integer string. IDX specifies the signature. Deprecated, use key
+ structure directly instead. */
+unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx,
+ _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+
+/* Crypto Operations. */
+
+/* Cancel a pending asynchronous operation. */
+gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx);
+
+
+struct _gpgme_invalid_key
+{
+ struct _gpgme_invalid_key *next;
+ char *fpr;
+ gpgme_error_t reason;
+};
+typedef struct _gpgme_invalid_key *gpgme_invalid_key_t;
+
+
+/* Encryption. */
+struct _gpgme_op_encrypt_result
+{
+ /* The list of invalid recipients. */
+ gpgme_invalid_key_t invalid_recipients;
+};
+typedef struct _gpgme_op_encrypt_result *gpgme_encrypt_result_t;
+
+/* Retrieve a pointer to the result of the encrypt operation. */
+gpgme_encrypt_result_t gpgme_op_encrypt_result (gpgme_ctx_t ctx);
+
+/* The valid encryption flags. */
+typedef enum
+ {
+ GPGME_ENCRYPT_ALWAYS_TRUST = 1
+ }
+gpgme_encrypt_flags_t;
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. */
+gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher);
+
+/* Encrypt plaintext PLAIN within CTX for the recipients RECP and
+ store the resulting ciphertext in CIPHER. Also sign the ciphertext
+ with the signers in CTX. */
+gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx,
+ gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain,
+ gpgme_data_t cipher);
+gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t cipher);
+
+
+/* Decryption. */
+struct _gpgme_op_decrypt_result
+{
+ char *unsupported_algorithm;
+
+ /* Key should not have been used for encryption. */
+ unsigned int wrong_key_usage : 1;
+
+ /* Internal to GPGME, do not use. */
+ int _unused : 31;
+};
+typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t;
+
+/* Retrieve a pointer to the result of the decrypt operation. */
+gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx);
+
+/* Decrypt ciphertext CIPHER within CTX and store the resulting
+ plaintext in PLAIN. */
+gpgme_error_t gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher,
+ gpgme_data_t plain);
+gpgme_error_t gpgme_op_decrypt (gpgme_ctx_t ctx,
+ gpgme_data_t cipher, gpgme_data_t plain);
+
+/* Decrypt ciphertext CIPHER and make a signature verification within
+ CTX and store the resulting plaintext in PLAIN. */
+gpgme_error_t gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx,
+ gpgme_data_t cipher,
+ gpgme_data_t plain);
+gpgme_error_t gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher,
+ gpgme_data_t plain);
+
+
+/* Signing. */
+struct _gpgme_new_signature
+{
+ struct _gpgme_new_signature *next;
+
+ /* The type of the signature. */
+ gpgme_sig_mode_t type;
+
+ /* The public key algorithm used to create the signature. */
+ gpgme_pubkey_algo_t pubkey_algo;
+
+ /* The hash algorithm used to create the signature. */
+ gpgme_hash_algo_t hash_algo;
+
+ /* Internal to GPGME, do not use. Must be set to the same value as
+ CLASS below. */
+ unsigned long _obsolete_class;
+
+ /* Signature creation time. */
+ long int timestamp;
+
+ /* The fingerprint of the signature. */
+ char *fpr;
+
+#ifdef __cplusplus
+ unsigned int _obsolete_class_2;
+#else
+ /* Must be set to SIG_CLASS below. */
+ unsigned int class _GPGME_DEPRECATED;
+#endif
+
+ /* Crypto backend specific signature class. */
+ unsigned int sig_class;
+};
+typedef struct _gpgme_new_signature *gpgme_new_signature_t;
+
+struct _gpgme_op_sign_result
+{
+ /* The list of invalid signers. */
+ gpgme_invalid_key_t invalid_signers;
+ gpgme_new_signature_t signatures;
+};
+typedef struct _gpgme_op_sign_result *gpgme_sign_result_t;
+
+/* Retrieve a pointer to the result of the signing operation. */
+gpgme_sign_result_t gpgme_op_sign_result (gpgme_ctx_t ctx);
+
+/* Sign the plaintext PLAIN and store the signature in SIG. */
+gpgme_error_t gpgme_op_sign_start (gpgme_ctx_t ctx,
+ gpgme_data_t plain, gpgme_data_t sig,
+ gpgme_sig_mode_t mode);
+gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx,
+ gpgme_data_t plain, gpgme_data_t sig,
+ gpgme_sig_mode_t mode);
+
+
+/* Verify. */
+struct _gpgme_sig_notation
+{
+ struct _gpgme_sig_notation *next;
+
+ /* If NAME is a null pointer, then VALUE contains a policy URL
+ rather than a notation. */
+ char *name;
+ char *value;
+};
+typedef struct _gpgme_sig_notation *gpgme_sig_notation_t;
+
+/* Flags used for the SUMMARY field in a gpgme_signature_t. */
+typedef enum
+ {
+ GPGME_SIGSUM_VALID = 0x0001, /* The signature is fully valid. */
+ GPGME_SIGSUM_GREEN = 0x0002, /* The signature is good. */
+ GPGME_SIGSUM_RED = 0x0004, /* The signature is bad. */
+ GPGME_SIGSUM_KEY_REVOKED = 0x0010, /* One key has been revoked. */
+ GPGME_SIGSUM_KEY_EXPIRED = 0x0020, /* One key has expired. */
+ GPGME_SIGSUM_SIG_EXPIRED = 0x0040, /* The signature has expired. */
+ GPGME_SIGSUM_KEY_MISSING = 0x0080, /* Can't verify: key missing. */
+ GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */
+ GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */
+ GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */
+ GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */
+ }
+gpgme_sigsum_t;
+
+struct _gpgme_signature
+{
+ struct _gpgme_signature *next;
+
+ /* A summary of the signature status. */
+ gpgme_sigsum_t summary;
+
+ /* The fingerprint or key ID of the signature. */
+ char *fpr;
+
+ /* The status of the signature. */
+ gpgme_error_t status;
+
+ /* Notation data and policy URLs. */
+ gpgme_sig_notation_t notations;
+
+ /* Signature creation time. */
+ unsigned long timestamp;
+
+ /* Signature exipration time or 0. */
+ unsigned long exp_timestamp;
+
+ /* Key should not have been used for signing. */
+ unsigned int wrong_key_usage : 1;
+
+ /* Internal to GPGME, do not use. */
+ int _unused : 31;
+
+ gpgme_validity_t validity;
+ gpgme_error_t validity_reason;
+};
+typedef struct _gpgme_signature *gpgme_signature_t;
+
+struct _gpgme_op_verify_result
+{
+ gpgme_signature_t signatures;
+};
+typedef struct _gpgme_op_verify_result *gpgme_verify_result_t;
+
+/* Retrieve a pointer to the result of the verify operation. */
+gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx);
+
+/* Verify within CTX that SIG is a valid signature for TEXT. */
+gpgme_error_t gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
+ gpgme_data_t signed_text,
+ gpgme_data_t plaintext);
+gpgme_error_t gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig,
+ gpgme_data_t signed_text,
+ gpgme_data_t plaintext);
+
+
+/* Import. */
+
+/* The key was new. */
+#define GPGME_IMPORT_NEW 1
+
+/* The key contained new user IDs. */
+#define GPGME_IMPORT_UID 2
+
+/* The key contained new signatures. */
+#define GPGME_IMPORT_SIG 4
+
+/* The key contained new sub keys. */
+#define GPGME_IMPORT_SUBKEY 8
+
+/* The key contained a secret key. */
+#define GPGME_IMPORT_SECRET 16
+
+
+struct _gpgme_import_status
+{
+ struct _gpgme_import_status *next;
+
+ /* Fingerprint. */
+ char *fpr;
+
+ /* If a problem occured, the reason why the key could not be
+ imported. Otherwise GPGME_No_Error. */
+ gpgme_error_t result;
+
+ /* The result of the import, the GPGME_IMPORT_* values bit-wise
+ ORed. 0 means the key was already known and no new components
+ have been added. */
+ unsigned int status;
+};
+typedef struct _gpgme_import_status *gpgme_import_status_t;
+
+/* Import. */
+struct _gpgme_op_import_result
+{
+ /* Number of considered keys. */
+ int considered;
+
+ /* Keys without user ID. */
+ int no_user_id;
+
+ /* Imported keys. */
+ int imported;
+
+ /* Imported RSA keys. */
+ int imported_rsa;
+
+ /* Unchanged keys. */
+ int unchanged;
+
+ /* Number of new user ids. */
+ int new_user_ids;
+
+ /* Number of new sub keys. */
+ int new_sub_keys;
+
+ /* Number of new signatures. */
+ int new_signatures;
+
+ /* Number of new revocations. */
+ int new_revocations;
+
+ /* Number of secret keys read. */
+ int secret_read;
+
+ /* Number of secret keys imported. */
+ int secret_imported;
+
+ /* Number of secret keys unchanged. */
+ int secret_unchanged;
+
+ /* Number of new keys skipped. */
+ int skipped_new_keys;
+
+ /* Number of keys not imported. */
+ int not_imported;
+
+ /* List of keys for which an import was attempted. */
+ gpgme_import_status_t imports;
+};
+typedef struct _gpgme_op_import_result *gpgme_import_result_t;
+
+/* Retrieve a pointer to the result of the import operation. */
+gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx);
+
+/* Import the key in KEYDATA into the keyring. */
+gpgme_error_t gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata);
+gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata);
+gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
+ int *nr) _GPGME_DEPRECATED;
+
+
+/* Export the keys found by PATTERN into KEYDATA. */
+gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
+ unsigned int reserved,
+ gpgme_data_t keydata);
+gpgme_error_t gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
+ unsigned int reserved, gpgme_data_t keydata);
+
+gpgme_error_t gpgme_op_export_ext_start (gpgme_ctx_t ctx,
+ const char *pattern[],
+ unsigned int reserved,
+ gpgme_data_t keydata);
+gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
+ unsigned int reserved,
+ gpgme_data_t keydata);
+
+
+/* Key generation. */
+struct _gpgme_op_genkey_result
+{
+ /* A primary key was generated. */
+ unsigned int primary : 1;
+
+ /* A sub key was generated. */
+ unsigned int sub : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 30;
+
+ /* The fingerprint of the generated key. */
+ char *fpr;
+};
+typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t;
+
+/* Generate a new keypair and add it to the keyring. PUBKEY and
+ SECKEY should be null for now. PARMS specifies what keys should be
+ generated. */
+gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms,
+ gpgme_data_t pubkey, gpgme_data_t seckey);
+gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms,
+ gpgme_data_t pubkey, gpgme_data_t seckey);
+
+/* Retrieve a pointer to the result of the genkey operation. */
+gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx);
+
+
+/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
+ keys are also deleted. */
+gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key,
+ int allow_secret);
+gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key,
+ int allow_secret);
+
+
+/* Edit the key KEY. Send status and command requests to FNC and
+ output of edit commands to OUT. */
+gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out);
+gpgme_error_t gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out);
+
+/* Edit the card for the key KEY. Send status and command requests to
+ FNC and output of edit commands to OUT. */
+gpgme_error_t gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out);
+gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
+ gpgme_edit_cb_t fnc, void *fnc_value,
+ gpgme_data_t out);
+
+
+/* Key management functions. */
+struct _gpgme_op_keylist_result
+{
+ unsigned int truncated : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 31;
+};
+typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t;
+
+/* Retrieve a pointer to the result of the key listing operation. */
+gpgme_keylist_result_t gpgme_op_keylist_result (gpgme_ctx_t ctx);
+
+/* Start a keylist operation within CTX, searching for keys which
+ match PATTERN. If SECRET_ONLY is true, only secret keys are
+ returned. */
+gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern,
+ int secret_only);
+gpgme_error_t gpgme_op_keylist_ext_start (gpgme_ctx_t ctx,
+ const char *pattern[],
+ int secret_only, int reserved);
+
+/* Return the next key from the keylist in R_KEY. */
+gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key);
+
+/* Terminate a pending keylist operation within CTX. */
+gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx);
+
+
+/* Trust items and operations. */
+
+struct _gpgme_trust_item
+{
+ /* Internal to GPGME, do not use. */
+ unsigned int _refs;
+
+ /* The key ID to which the trust item belongs. */
+ char *keyid;
+
+ /* Internal to GPGME, do not use. */
+ char _keyid[16 + 1];
+
+ /* The type of the trust item, 1 refers to a key, 2 to a user ID. */
+ int type;
+
+ /* The trust level. */
+ int level;
+
+ /* The owner trust if TYPE is 1. */
+ char *owner_trust;
+
+ /* Internal to GPGME, do not use. */
+ char _owner_trust[2];
+
+ /* The calculated validity. */
+ char *validity;
+
+ /* Internal to GPGME, do not use. */
+ char _validity[2];
+
+ /* The user name if TYPE is 2. */
+ char *name;
+};
+typedef struct _gpgme_trust_item *gpgme_trust_item_t;
+
+/* Start a trustlist operation within CTX, searching for trust items
+ which match PATTERN. */
+gpgme_error_t gpgme_op_trustlist_start (gpgme_ctx_t ctx,
+ const char *pattern, int max_level);
+
+/* Return the next trust item from the trustlist in R_ITEM. */
+gpgme_error_t gpgme_op_trustlist_next (gpgme_ctx_t ctx,
+ gpgme_trust_item_t *r_item);
+
+/* Terminate a pending trustlist operation within CTX. */
+gpgme_error_t gpgme_op_trustlist_end (gpgme_ctx_t ctx);
+
+/* Acquire a reference to ITEM. */
+void gpgme_trust_item_ref (gpgme_trust_item_t item);
+
+/* Release a reference to ITEM. If this was the last one the trust
+ item is destroyed. */
+void gpgme_trust_item_unref (gpgme_trust_item_t item);
+
+/* Release the trust item ITEM. Deprecated, use
+ gpgme_trust_item_unref. */
+void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED;
+
+/* Return the value of the attribute WHAT of ITEM, which has to be
+ representable by a string. Deprecated, use trust item structure
+ directly. */
+const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
+ _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+/* Return the value of the attribute WHAT of KEY, which has to be
+ representable by an integer. IDX specifies a running index if the
+ attribute appears more than once in the key. Deprecated, use trust
+ item structure directly. */
+int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what,
+ const void *reserved, int idx)
+ _GPGME_DEPRECATED;
+
+
+/* Various functions. */
+
+/* Check that the library fulfills the version requirement. */
+const char *gpgme_check_version (const char *req_version);
+
+/* Retrieve information about the backend engines. */
+gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *engine_info);
+
+
+/* Engine support functions. */
+
+/* Verify that the engine implementing PROTO is installed and
+ available. */
+gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto);
+
+
+/* Deprecated types. */
+typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED;
+typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED;
+typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED;
+typedef gpgme_data_encoding_t GpgmeDataEncoding _GPGME_DEPRECATED;
+typedef gpgme_pubkey_algo_t GpgmePubKeyAlgo _GPGME_DEPRECATED;
+typedef gpgme_hash_algo_t GpgmeHashAlgo _GPGME_DEPRECATED;
+typedef gpgme_sig_stat_t GpgmeSigStat _GPGME_DEPRECATED;
+typedef gpgme_sig_mode_t GpgmeSigMode _GPGME_DEPRECATED;
+typedef gpgme_attr_t GpgmeAttr _GPGME_DEPRECATED;
+typedef gpgme_validity_t GpgmeValidity _GPGME_DEPRECATED;
+typedef gpgme_protocol_t GpgmeProtocol _GPGME_DEPRECATED;
+typedef gpgme_engine_info_t GpgmeEngineInfo _GPGME_DEPRECATED;
+typedef gpgme_subkey_t GpgmeSubkey _GPGME_DEPRECATED;
+typedef gpgme_key_sig_t GpgmeKeySig _GPGME_DEPRECATED;
+typedef gpgme_user_id_t GpgmeUserID _GPGME_DEPRECATED;
+typedef gpgme_key_t GpgmeKey _GPGME_DEPRECATED;
+typedef gpgme_passphrase_cb_t GpgmePassphraseCb _GPGME_DEPRECATED;
+typedef gpgme_progress_cb_t GpgmeProgressCb _GPGME_DEPRECATED;
+typedef gpgme_io_cb_t GpgmeIOCb _GPGME_DEPRECATED;
+typedef gpgme_register_io_cb_t GpgmeRegisterIOCb _GPGME_DEPRECATED;
+typedef gpgme_remove_io_cb_t GpgmeRemoveIOCb _GPGME_DEPRECATED;
+typedef gpgme_event_io_t GpgmeEventIO _GPGME_DEPRECATED;
+typedef gpgme_event_io_cb_t GpgmeEventIOCb _GPGME_DEPRECATED;
+#define GpgmeIOCbs gpgme_io_cbs
+typedef gpgme_data_read_cb_t GpgmeDataReadCb _GPGME_DEPRECATED;
+typedef gpgme_data_write_cb_t GpgmeDataWriteCb _GPGME_DEPRECATED;
+typedef gpgme_data_seek_cb_t GpgmeDataSeekCb _GPGME_DEPRECATED;
+typedef gpgme_data_release_cb_t GpgmeDataReleaseCb _GPGME_DEPRECATED;
+#define GpgmeDataCbs gpgme_data_cbs
+typedef gpgme_encrypt_result_t GpgmeEncryptResult _GPGME_DEPRECATED;
+typedef gpgme_sig_notation_t GpgmeSigNotation _GPGME_DEPRECATED;
+typedef gpgme_signature_t GpgmeSignature _GPGME_DEPRECATED;
+typedef gpgme_verify_result_t GpgmeVerifyResult _GPGME_DEPRECATED;
+typedef gpgme_import_status_t GpgmeImportStatus _GPGME_DEPRECATED;
+typedef gpgme_import_result_t GpgmeImportResult _GPGME_DEPRECATED;
+typedef gpgme_genkey_result_t GpgmeGenKeyResult _GPGME_DEPRECATED;
+typedef gpgme_trust_item_t GpgmeTrustItem _GPGME_DEPRECATED;
+typedef gpgme_status_code_t GpgmeStatusCode _GPGME_DEPRECATED;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GPGME_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/gpgme.m4 b/branches/gpgme-1-0-branch/gpgme/gpgme.m4
new file mode 100644
index 00000000..1915f550
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/gpgme.m4
@@ -0,0 +1,236 @@
+# gpgme.m4 - autoconf macro to detect GPGME.
+# Copyright (C) 2002, 2003, 2004 g10 Code GmbH
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+
+AC_DEFUN([_AM_PATH_GPGME_CONFIG],
+[ AC_ARG_WITH(gpgme-prefix,
+ AC_HELP_STRING([--with-gpgme-prefix=PFX],
+ [prefix where GPGME is installed (optional)]),
+ gpgme_config_prefix="$withval", gpgme_config_prefix="")
+ if test "x$gpgme_config_prefix" != x ; then
+ GPGME_CONFIG="$gpgme_config_prefix/bin/gpgme-config"
+ fi
+ AC_PATH_PROG(GPGME_CONFIG, gpgme-config, no)
+
+ gpgme_version=`$GPGME_CONFIG --version`
+ gpgme_version_major=`echo $gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'`
+ gpgme_version_minor=`echo $gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'`
+ gpgme_version_micro=`echo $gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'`
+])
+
+dnl AM_PATH_GPGME([MINIMUM-VERSION,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgpgme and define GPGME_CFLAGS and GPGME_LIBS.
+dnl
+AC_DEFUN([AM_PATH_GPGME],
+[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl
+ tmp=ifelse([$1], ,1:0.4.2,$1)
+ if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+ req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
+ min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+ else
+ req_gpgme_api=0
+ min_gpgme_version="$tmp"
+ fi
+
+ AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version)
+ ok=no
+ if test "$GPGME_CONFIG" != "no" ; then
+ req_major=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ if test "$gpgme_version_major" -gt "$req_major"; then
+ ok=yes
+ else
+ if test "$gpgme_version_major" -eq "$req_major"; then
+ if test "$gpgme_version_minor" -gt "$req_minor"; then
+ ok=yes
+ else
+ if test "$gpgme_version_minor" -eq "$req_minor"; then
+ if test "$gpgme_version_micro" -ge "$req_micro"; then
+ ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ # If we have a recent GPGME, we should also check that the
+ # API is compatible.
+ if test "$req_gpgme_api" -gt 0 ; then
+ tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0`
+ if test "$tmp" -gt 0 ; then
+ if test "$req_gpgme_api" -ne "$tmp" ; then
+ ok=no
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ GPGME_CFLAGS=`$GPGME_CONFIG --cflags`
+ GPGME_LIBS=`$GPGME_CONFIG --libs`
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ GPGME_CFLAGS=""
+ GPGME_LIBS=""
+ AC_MSG_RESULT(no)
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(GPGME_CFLAGS)
+ AC_SUBST(GPGME_LIBS)
+])
+
+dnl AM_PATH_GPGME_PTH([MINIMUM-VERSION,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgpgme and define GPGME_PTH_CFLAGS and GPGME_PTH_LIBS.
+dnl
+AC_DEFUN([AM_PATH_GPGME_PTH],
+[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl
+ tmp=ifelse([$1], ,1:0.4.2,$1)
+ if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+ req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
+ min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+ else
+ req_gpgme_api=0
+ min_gpgme_version="$tmp"
+ fi
+
+ AC_MSG_CHECKING(for GPGME Pth - version >= $min_gpgme_version)
+ ok=no
+ if test "$GPGME_CONFIG" != "no" ; then
+ if `$GPGME_CONFIG --thread=pth 2> /dev/null` ; then
+ req_major=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ if test "$gpgme_version_major" -gt "$req_major"; then
+ ok=yes
+ else
+ if test "$gpgme_version_major" -eq "$req_major"; then
+ if test "$gpgme_version_minor" -gt "$req_minor"; then
+ ok=yes
+ else
+ if test "$gpgme_version_minor" -eq "$req_minor"; then
+ if test "$gpgme_version_micro" -ge "$req_micro"; then
+ ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ # If we have a recent GPGME, we should also check that the
+ # API is compatible.
+ if test "$req_gpgme_api" -gt 0 ; then
+ tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0`
+ if test "$tmp" -gt 0 ; then
+ if test "$req_gpgme_api" -ne "$tmp" ; then
+ ok=no
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ GPGME_PTH_CFLAGS=`$GPGME_CONFIG --thread=pth --cflags`
+ GPGME_PTH_LIBS=`$GPGME_CONFIG --thread=pth --libs`
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ GPGME_PTH_CFLAGS=""
+ GPGME_PTH_LIBS=""
+ AC_MSG_RESULT(no)
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(GPGME_PTH_CFLAGS)
+ AC_SUBST(GPGME_PTH_LIBS)
+])
+
+dnl AM_PATH_GPGME_PTHREAD([MINIMUM-VERSION,
+dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libgpgme and define GPGME_PTHREAD_CFLAGS
+dnl and GPGME_PTHREAD_LIBS.
+dnl
+AC_DEFUN([AM_PATH_GPGME_PTHREAD],
+[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl
+ tmp=ifelse([$1], ,1:0.4.2,$1)
+ if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then
+ req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'`
+ min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'`
+ else
+ req_gpgme_api=0
+ min_gpgme_version="$tmp"
+ fi
+
+ AC_MSG_CHECKING(for GPGME pthread - version >= $min_gpgme_version)
+ ok=no
+ if test "$GPGME_CONFIG" != "no" ; then
+ if `$GPGME_CONFIG --thread=pthread 2> /dev/null` ; then
+ req_major=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`
+ req_minor=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'`
+ req_micro=`echo $min_gpgme_version | \
+ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'`
+ if test "$gpgme_version_major" -gt "$req_major"; then
+ ok=yes
+ else
+ if test "$gpgme_version_major" -eq "$req_major"; then
+ if test "$gpgme_version_minor" -gt "$req_minor"; then
+ ok=yes
+ else
+ if test "$gpgme_version_minor" -eq "$req_minor"; then
+ if test "$gpgme_version_micro" -ge "$req_micro"; then
+ ok=yes
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ # If we have a recent GPGME, we should also check that the
+ # API is compatible.
+ if test "$req_gpgme_api" -gt 0 ; then
+ tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0`
+ if test "$tmp" -gt 0 ; then
+ if test "$req_gpgme_api" -ne "$tmp" ; then
+ ok=no
+ fi
+ fi
+ fi
+ fi
+ if test $ok = yes; then
+ GPGME_PTHREAD_CFLAGS=`$GPGME_CONFIG --thread=pthread --cflags`
+ GPGME_PTHREAD_LIBS=`$GPGME_CONFIG --thread=pthread --libs`
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ GPGME_PTHREAD_CFLAGS=""
+ GPGME_PTHREAD_LIBS=""
+ AC_MSG_RESULT(no)
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(GPGME_PTHREAD_CFLAGS)
+ AC_SUBST(GPGME_PTHREAD_LIBS)
+])
diff --git a/branches/gpgme-1-0-branch/gpgme/import.c b/branches/gpgme-1-0-branch/gpgme/import.c
new file mode 100644
index 00000000..46ae72e5
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/import.c
@@ -0,0 +1,272 @@
+/* import.c - Import a key.
+ 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 <errno.h>
+#include <string.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_import_result result;
+
+ /* A pointer to the next pointer of the last import status in the
+ list. This makes appending new imports painless while preserving
+ the order. */
+ gpgme_import_status_t *lastp;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+ gpgme_import_status_t import = opd->result.imports;
+
+ while (import)
+ {
+ gpgme_import_status_t next = import->next;
+ free (import->fpr);
+ free (import);
+ import = next;
+ }
+}
+
+
+gpgme_import_result_t
+gpgme_op_import_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+static gpgme_error_t
+parse_import (char *args, gpgme_import_status_t *import_status, int problem)
+{
+ gpgme_import_status_t import;
+ char *tail;
+ long int nr;
+
+ import = malloc (sizeof (*import));
+ if (!import)
+ return gpg_error_from_errno (errno);
+ import->next = NULL;
+
+ errno = 0;
+ nr = strtol (args, &tail, 0);
+ if (errno || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (import);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ args = tail;
+
+ if (problem)
+ {
+ switch (nr)
+ {
+ case 0:
+ case 4:
+ default:
+ import->result = gpg_error (GPG_ERR_GENERAL);
+ break;
+
+ case 1:
+ import->result = gpg_error (GPG_ERR_BAD_CERT);
+ break;
+
+ case 2:
+ import->result = gpg_error (GPG_ERR_MISSING_CERT);
+ break;
+
+ case 3:
+ import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
+ break;
+ }
+ import->status = 0;
+ }
+ else
+ {
+ import->result = gpg_error (GPG_ERR_NO_ERROR);
+ import->status = nr;
+ }
+
+ while (*args == ' ')
+ args++;
+ tail = strchr (args, ' ');
+ if (tail)
+ *tail = '\0';
+
+ import->fpr = strdup (args);
+ if (!import->fpr)
+ {
+ int saved_errno = errno;
+ free (import);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ *import_status = import;
+ return 0;
+}
+
+
+
+gpgme_error_t
+parse_import_res (char *args, gpgme_import_result_t result)
+{
+ char *tail;
+
+ errno = 0;
+
+#define PARSE_NEXT(x) \
+ (x) = strtol (args, &tail, 0); \
+ if (errno || args == tail || *tail != ' ') \
+ /* The crypto backend does not behave. */ \
+ return gpg_error (GPG_ERR_INV_ENGINE); \
+ args = tail;
+
+ PARSE_NEXT (result->considered);
+ PARSE_NEXT (result->no_user_id);
+ PARSE_NEXT (result->imported);
+ PARSE_NEXT (result->imported_rsa);
+ PARSE_NEXT (result->unchanged);
+ PARSE_NEXT (result->new_user_ids);
+ PARSE_NEXT (result->new_sub_keys);
+ PARSE_NEXT (result->new_signatures);
+ PARSE_NEXT (result->new_revocations);
+ PARSE_NEXT (result->secret_read);
+ PARSE_NEXT (result->secret_imported);
+ PARSE_NEXT (result->secret_unchanged);
+ PARSE_NEXT (result->skipped_new_keys);
+ PARSE_NEXT (result->not_imported);
+
+ return 0;
+}
+
+
+static gpgme_error_t
+import_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_IMPORT_OK:
+ case GPGME_STATUS_IMPORT_PROBLEM:
+ err = parse_import (args, opd->lastp,
+ code == GPGME_STATUS_IMPORT_OK ? 0 : 1);
+ if (err)
+ return err;
+
+ opd->lastp = &(*opd->lastp)->next;
+ break;
+
+ case GPGME_STATUS_IMPORT_RES:
+ err = parse_import_res (args, &opd->result);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+_gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+ opd->lastp = &opd->result.imports;
+
+ if (!keydata)
+ return gpg_error (GPG_ERR_NO_DATA);
+
+ _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
+
+ return _gpgme_engine_op_import (ctx->engine, keydata);
+}
+
+
+gpgme_error_t
+gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata)
+{
+ return _gpgme_op_import_start (ctx, 0, keydata);
+}
+
+
+/* Import the key in KEYDATA into the keyring. */
+gpgme_error_t
+gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata)
+{
+ gpgme_error_t err = _gpgme_op_import_start (ctx, 1, keydata);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+gpgme_error_t
+gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr)
+{
+ gpgme_error_t err = gpgme_op_import (ctx, keydata);
+ if (!err && nr)
+ {
+ gpgme_import_result_t result = gpgme_op_import_result (ctx);
+ *nr = result->considered;
+ }
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/io.h b/branches/gpgme-1-0-branch/gpgme/io.h
new file mode 100644
index 00000000..9cc5eb25
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/io.h
@@ -0,0 +1,65 @@
+/* io.h - Interface to the I/O functions.
+ 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 IO_H
+#define IO_H
+
+/* A single file descriptor passed to spawn. For child fds, dup_to
+ specifies the fd it should become in the child. */
+struct spawn_fd_item_s
+{
+ int fd;
+ int dup_to;
+};
+
+struct io_select_fd_s
+{
+ int fd;
+ int for_read;
+ int for_write;
+ int signaled;
+ int frozen;
+ void *opaque;
+};
+
+/* These function are either defined in posix-io.c or w32-io.c. */
+void _gpgme_io_subsystem_init (void);
+int _gpgme_io_read (int fd, void *buffer, size_t count);
+int _gpgme_io_write (int fd, const void *buffer, size_t count);
+int _gpgme_io_pipe (int filedes[2], int inherit_idx);
+int _gpgme_io_close (int fd);
+int _gpgme_io_set_close_notify (int fd, void (*handler) (int, void *),
+ void *value);
+int _gpgme_io_set_nonblocking (int fd);
+
+/* Spawn the executable PATH with ARGV as arguments, after forking
+ close all fds in FD_PARENT_LIST in the parent and close or dup all
+ fds in FD_CHILD_LIST in the child. */
+int _gpgme_io_spawn (const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list);
+int _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal);
+int _gpgme_io_kill (int pid, int hard);
+int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock);
+
+#endif /* IO_H */
+
+
+
diff --git a/branches/gpgme-1-0-branch/gpgme/isascii.c b/branches/gpgme-1-0-branch/gpgme/isascii.c
new file mode 100644
index 00000000..565c7166
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/isascii.c
@@ -0,0 +1,29 @@
+/* isascii.c - Replacement for isascii.
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int
+isascii (int c)
+{
+ return (((c) & ~0x7f) == 0);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/key.c b/branches/gpgme-1-0-branch/gpgme/key.c
new file mode 100644
index 00000000..444f0679
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/key.c
@@ -0,0 +1,711 @@
+/* key.c - Key objects.
+ 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 <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "util.h"
+#include "ops.h"
+#include "sema.h"
+
+
+/* Protects all reference counters in keys. All other accesses to a
+ key are read only. */
+DEFINE_STATIC_LOCK (key_ref_lock);
+
+
+/* Create a new key. */
+gpgme_error_t
+_gpgme_key_new (gpgme_key_t *r_key)
+{
+ gpgme_key_t key;
+
+ key = calloc (1, sizeof *key);
+ if (!key)
+ return gpg_error_from_errno (errno);
+ key->_refs = 1;
+
+ *r_key = key;
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_key_add_subkey (gpgme_key_t key, gpgme_subkey_t *r_subkey)
+{
+ gpgme_subkey_t subkey;
+
+ subkey = calloc (1, sizeof *subkey);
+ if (!subkey)
+ return gpg_error_from_errno (errno);
+ subkey->keyid = subkey->_keyid;
+ subkey->_keyid[16] = '\0';
+
+ if (!key->subkeys)
+ key->subkeys = subkey;
+ if (key->_last_subkey)
+ key->_last_subkey->next = subkey;
+ key->_last_subkey = subkey;
+
+ *r_subkey = subkey;
+ return 0;
+}
+
+
+static char *
+set_user_id_part (char *tail, const char *buf, size_t len)
+{
+ while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t'))
+ len--;
+ for (; len; len--)
+ *tail++ = *buf++;
+ *tail++ = 0;
+ return tail;
+}
+
+
+static void
+parse_user_id (char *src, char **name, char **email,
+ char **comment, char *tail)
+{
+ const char *start = NULL;
+ int in_name = 0;
+ int in_email = 0;
+ int in_comment = 0;
+
+ while (*src)
+ {
+ if (in_email)
+ {
+ if (*src == '<')
+ /* Not legal but anyway. */
+ in_email++;
+ else if (*src == '>')
+ {
+ if (!--in_email && !*email)
+ {
+ *email = tail;
+ tail = set_user_id_part (tail, start, src - start);
+ }
+ }
+ }
+ else if (in_comment)
+ {
+ if (*src == '(')
+ in_comment++;
+ else if (*src == ')')
+ {
+ if (!--in_comment && !*comment)
+ {
+ *comment = tail;
+ tail = set_user_id_part (tail, start, src - start);
+ }
+ }
+ }
+ else if (*src == '<')
+ {
+ if (in_name)
+ {
+ if (!*name)
+ {
+ *name = tail;
+ tail = set_user_id_part (tail, start, src - start);
+ }
+ in_name = 0;
+ }
+ in_email = 1;
+ start = src + 1;
+ }
+ else if (*src == '(')
+ {
+ if (in_name)
+ {
+ if (!*name)
+ {
+ *name = tail;
+ tail = set_user_id_part (tail, start, src - start);
+ }
+ in_name = 0;
+ }
+ in_comment = 1;
+ start = src + 1;
+ }
+ else if (!in_name && *src != ' ' && *src != '\t')
+ {
+ in_name = 1;
+ start = src;
+ }
+ src++;
+ }
+
+ if (in_name)
+ {
+ if (!*name)
+ {
+ *name = tail;
+ tail = set_user_id_part (tail, start, src - start);
+ }
+ }
+
+ /* Let unused parts point to an EOS. */
+ tail--;
+ if (!*name)
+ *name = tail;
+ if (!*email)
+ *email = tail;
+ if (!*comment)
+ *comment = tail;
+}
+
+
+static void
+parse_x509_user_id (char *src, char **name, char **email,
+ char **comment, char *tail)
+{
+ if (*src == '<' && src[strlen (src) - 1] == '>')
+ *email = src;
+
+ /* Let unused parts point to an EOS. */
+ tail--;
+ if (!*name)
+ *name = tail;
+ if (!*email)
+ *email = tail;
+ if (!*comment)
+ *comment = tail;
+}
+
+
+/* Take a name from the --with-colon listing, remove certain escape
+ sequences sequences and put it into the list of UIDs. */
+gpgme_error_t
+_gpgme_key_append_name (gpgme_key_t key, char *src)
+{
+ gpgme_user_id_t uid;
+ char *dst;
+ int src_len = strlen (src);
+
+ assert (key);
+ /* We can malloc a buffer of the same length, because the converted
+ string will never be larger. Actually we allocate it twice the
+ size, so that we are able to store the parsed stuff there too. */
+ uid = malloc (sizeof (*uid) + 2 * src_len + 3);
+ if (!uid)
+ return gpg_error_from_errno (errno);
+ memset (uid, 0, sizeof *uid);
+
+ uid->uid = ((char *) uid) + sizeof (*uid);
+ dst = uid->uid;
+ _gpgme_decode_c_string (src, &dst, src_len + 1);
+
+ dst += strlen (dst) + 1;
+ if (key->protocol == GPGME_PROTOCOL_CMS)
+ parse_x509_user_id (uid->uid, &uid->name, &uid->email,
+ &uid->comment, dst);
+ else
+ parse_user_id (uid->uid, &uid->name, &uid->email,
+ &uid->comment, dst);
+
+ if (!key->uids)
+ key->uids = uid;
+ if (key->_last_uid)
+ key->_last_uid->next = uid;
+ key->_last_uid = uid;
+
+ return 0;
+}
+
+
+gpgme_key_sig_t
+_gpgme_key_add_sig (gpgme_key_t key, char *src)
+{
+ int src_len = src ? strlen (src) : 0;
+ gpgme_user_id_t uid;
+ gpgme_key_sig_t sig;
+
+ assert (key); /* XXX */
+
+ uid = key->_last_uid;
+ assert (uid); /* XXX */
+
+ /* We can malloc a buffer of the same length, because the converted
+ string will never be larger. Actually we allocate it twice the
+ size, so that we are able to store the parsed stuff there too. */
+ sig = malloc (sizeof (*sig) + 2 * src_len + 3);
+ if (!sig)
+ return NULL;
+ memset (sig, 0, sizeof *sig);
+
+ sig->keyid = sig->_keyid;
+ sig->_keyid[16] = '\0';
+ sig->uid = ((char *) sig) + sizeof (*sig);
+
+ if (src)
+ {
+ char *dst = sig->uid;
+ _gpgme_decode_c_string (src, &dst, src_len + 1);
+ dst += strlen (dst) + 1;
+ if (key->protocol == GPGME_PROTOCOL_CMS)
+ parse_x509_user_id (sig->uid, &sig->name, &sig->email,
+ &sig->comment, dst);
+ else
+ parse_user_id (sig->uid, &sig->name, &sig->email,
+ &sig->comment, dst);
+ }
+
+ if (!uid->signatures)
+ uid->signatures = sig;
+ if (uid->_last_keysig)
+ uid->_last_keysig->next = sig;
+ uid->_last_keysig = sig;
+
+ return sig;
+}
+
+
+/* Acquire a reference to KEY. */
+void
+gpgme_key_ref (gpgme_key_t key)
+{
+ LOCK (key_ref_lock);
+ key->_refs++;
+ UNLOCK (key_ref_lock);
+}
+
+
+/* gpgme_key_unref releases the key object. Note, that this function
+ may not do an actual release if there are other shallow copies of
+ the objects. You have to call this function for every newly
+ created key object as well as for every gpgme_key_ref() done on the
+ key object. */
+void
+gpgme_key_unref (gpgme_key_t key)
+{
+ gpgme_user_id_t uid;
+ gpgme_subkey_t subkey;
+
+ if (!key)
+ return;
+
+ LOCK (key_ref_lock);
+ assert (key->_refs > 0);
+ if (--key->_refs)
+ {
+ UNLOCK (key_ref_lock);
+ return;
+ }
+ UNLOCK (key_ref_lock);
+
+ subkey = key->subkeys;
+ while (subkey)
+ {
+ gpgme_subkey_t next = subkey->next;
+ if (subkey->fpr)
+ free (subkey->fpr);
+ free (subkey);
+ subkey = next;
+ }
+
+ uid = key->uids;
+ while (uid)
+ {
+ gpgme_user_id_t next_uid = uid->next;
+ gpgme_key_sig_t keysig = uid->signatures;
+
+ while (keysig)
+ {
+ gpgme_key_sig_t next = keysig->next;
+ free (keysig);
+ keysig = next;
+ }
+ free (uid);
+ uid = next_uid;
+ }
+
+ if (key->issuer_serial)
+ free (key->issuer_serial);
+ if (key->issuer_name)
+ free (key->issuer_name);
+
+ if (key->chain_id)
+ free (key->chain_id);
+
+ free (key);
+}
+
+
+/* Compatibility interfaces. */
+
+void
+gpgme_key_release (gpgme_key_t key)
+{
+ gpgme_key_unref (key);
+}
+
+
+static const char *
+otrust_to_string (int otrust)
+{
+ switch (otrust)
+ {
+ case GPGME_VALIDITY_NEVER:
+ return "n";
+
+ case GPGME_VALIDITY_MARGINAL:
+ return "m";
+
+ case GPGME_VALIDITY_FULL:
+ return "f";
+
+ case GPGME_VALIDITY_ULTIMATE:
+ return "u";
+
+ default:
+ return "?";
+ }
+}
+
+
+static const char *
+validity_to_string (int validity)
+{
+ switch (validity)
+ {
+ case GPGME_VALIDITY_UNDEFINED:
+ return "q";
+
+ case GPGME_VALIDITY_NEVER:
+ return "n";
+
+ case GPGME_VALIDITY_MARGINAL:
+ return "m";
+
+ case GPGME_VALIDITY_FULL:
+ return "f";
+
+ case GPGME_VALIDITY_ULTIMATE:
+ return "u";
+
+ case GPGME_VALIDITY_UNKNOWN:
+ default:
+ return "?";
+ }
+}
+
+
+static const char *
+capabilities_to_string (gpgme_subkey_t subkey)
+{
+ static const char *const strings[8] =
+ {
+ "",
+ "c",
+ "s",
+ "sc",
+ "e",
+ "ec",
+ "es",
+ "esc"
+ };
+ return strings[(!!subkey->can_encrypt << 2)
+ | (!!subkey->can_sign << 1)
+ | (!!subkey->can_certify)];
+}
+
+
+/* Return the value of the attribute WHAT of ITEM, which has to be
+ representable by a string. */
+const char *
+gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ gpgme_subkey_t subkey;
+ gpgme_user_id_t uid;
+ int i;
+
+ if (!key || reserved || idx < 0)
+ return NULL;
+
+ /* Select IDXth subkey. */
+ subkey = key->subkeys;
+ for (i = 0; i < idx; i++)
+ {
+ subkey = subkey->next;
+ if (!subkey)
+ break;
+ }
+
+ /* Select the IDXth user ID. */
+ uid = key->uids;
+ for (i = 0; i < idx; i++)
+ {
+ uid = uid->next;
+ if (!uid)
+ break;
+ }
+
+ switch (what)
+ {
+ case GPGME_ATTR_KEYID:
+ return subkey ? subkey->keyid : NULL;
+
+ case GPGME_ATTR_FPR:
+ return subkey ? subkey->fpr : NULL;
+
+ case GPGME_ATTR_ALGO:
+ return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL;
+
+ case GPGME_ATTR_TYPE:
+ return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP";
+
+ case GPGME_ATTR_OTRUST:
+ return otrust_to_string (key->owner_trust);
+
+ case GPGME_ATTR_USERID:
+ return uid ? uid->uid : NULL;
+
+ case GPGME_ATTR_NAME:
+ return uid ? uid->name : NULL;
+
+ case GPGME_ATTR_EMAIL:
+ return uid ? uid->email : NULL;
+
+ case GPGME_ATTR_COMMENT:
+ return uid ? uid->comment : NULL;
+
+ case GPGME_ATTR_VALIDITY:
+ return uid ? validity_to_string (uid->validity) : NULL;
+
+ case GPGME_ATTR_KEY_CAPS:
+ return subkey ? capabilities_to_string (subkey) : NULL;
+
+ case GPGME_ATTR_SERIAL:
+ return key->issuer_serial;
+
+ case GPGME_ATTR_ISSUER:
+ return idx ? NULL : key->issuer_name;
+
+ case GPGME_ATTR_CHAINID:
+ return key->chain_id;
+
+ default:
+ return NULL;
+ }
+}
+
+
+unsigned long
+gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ gpgme_subkey_t subkey;
+ gpgme_user_id_t uid;
+ int i;
+
+ if (!key || reserved || idx < 0)
+ return 0;
+
+ /* Select IDXth subkey. */
+ subkey = key->subkeys;
+ for (i = 0; i < idx; i++)
+ {
+ subkey = subkey->next;
+ if (!subkey)
+ break;
+ }
+
+ /* Select the IDXth user ID. */
+ uid = key->uids;
+ for (i = 0; i < idx; i++)
+ {
+ uid = uid->next;
+ if (!uid)
+ break;
+ }
+
+ switch (what)
+ {
+ case GPGME_ATTR_ALGO:
+ return subkey ? (unsigned long) subkey->pubkey_algo : 0;
+
+ case GPGME_ATTR_LEN:
+ return subkey ? (unsigned long) subkey->length : 0;
+
+ case GPGME_ATTR_TYPE:
+ return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0;
+
+ case GPGME_ATTR_CREATED:
+ return (subkey && subkey->timestamp >= 0)
+ ? (unsigned long) subkey->timestamp : 0;
+
+ case GPGME_ATTR_EXPIRE:
+ return (subkey && subkey->expires >= 0)
+ ? (unsigned long) subkey->expires : 0;
+
+ case GPGME_ATTR_VALIDITY:
+ return uid ? uid->validity : 0;
+
+ case GPGME_ATTR_OTRUST:
+ return key->owner_trust;
+
+ case GPGME_ATTR_IS_SECRET:
+ return !!key->secret;
+
+ case GPGME_ATTR_KEY_REVOKED:
+ return subkey ? subkey->revoked : 0;
+
+ case GPGME_ATTR_KEY_INVALID:
+ return subkey ? subkey->invalid : 0;
+
+ case GPGME_ATTR_KEY_EXPIRED:
+ return subkey ? subkey->expired : 0;
+
+ case GPGME_ATTR_KEY_DISABLED:
+ return subkey ? subkey->disabled : 0;
+
+ case GPGME_ATTR_UID_REVOKED:
+ return uid ? uid->revoked : 0;
+
+ case GPGME_ATTR_UID_INVALID:
+ return uid ? uid->invalid : 0;
+
+ case GPGME_ATTR_CAN_ENCRYPT:
+ return key->can_encrypt;
+
+ case GPGME_ATTR_CAN_SIGN:
+ return key->can_sign;
+
+ case GPGME_ATTR_CAN_CERTIFY:
+ return key->can_certify;
+
+ default:
+ return 0;
+ }
+}
+
+
+static gpgme_key_sig_t
+get_keysig (gpgme_key_t key, int uid_idx, int idx)
+{
+ gpgme_user_id_t uid;
+ gpgme_key_sig_t sig;
+
+ if (!key || uid_idx < 0 || idx < 0)
+ return NULL;
+
+ uid = key->uids;
+ while (uid && uid_idx > 0)
+ {
+ uid = uid->next;
+ uid_idx--;
+ }
+ if (!uid)
+ return NULL;
+
+ sig = uid->signatures;
+ while (sig && idx > 0)
+ {
+ sig = sig->next;
+ idx--;
+ }
+ return sig;
+}
+
+
+const char *
+gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx,
+ _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
+
+ if (!certsig || reserved)
+ return NULL;
+
+ switch (what)
+ {
+ case GPGME_ATTR_KEYID:
+ return certsig->keyid;
+
+ case GPGME_ATTR_ALGO:
+ return gpgme_pubkey_algo_name (certsig->pubkey_algo);
+
+ case GPGME_ATTR_USERID:
+ return certsig->uid;
+
+ case GPGME_ATTR_NAME:
+ return certsig->name;
+
+ case GPGME_ATTR_EMAIL:
+ return certsig->email;
+
+ case GPGME_ATTR_COMMENT:
+ return certsig->comment;
+
+ default:
+ return NULL;
+ }
+}
+
+
+unsigned long
+gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx);
+
+ if (!certsig || reserved)
+ return 0;
+
+ switch (what)
+ {
+ case GPGME_ATTR_ALGO:
+ return (unsigned long) certsig->pubkey_algo;
+
+ case GPGME_ATTR_CREATED:
+ return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp;
+
+ case GPGME_ATTR_EXPIRE:
+ return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires;
+
+ case GPGME_ATTR_KEY_REVOKED:
+ return certsig->revoked;
+
+ case GPGME_ATTR_KEY_INVALID:
+ return certsig->invalid;
+
+ case GPGME_ATTR_KEY_EXPIRED:
+ return certsig->expired;
+
+ case GPGME_ATTR_SIG_CLASS:
+ return certsig->sig_class;
+
+ case GPGME_ATTR_SIG_STATUS:
+ return certsig->status;
+
+ default:
+ return 0;
+ }
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/keylist.c b/branches/gpgme-1-0-branch/gpgme/keylist.c
new file mode 100644
index 00000000..57dda54a
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/keylist.c
@@ -0,0 +1,874 @@
+/* keylist.c - Listing keys.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+#include "debug.h"
+
+
+struct key_queue_item_s
+{
+ struct key_queue_item_s *next;
+ gpgme_key_t key;
+};
+
+typedef struct
+{
+ struct _gpgme_op_keylist_result result;
+
+ gpgme_key_t tmp_key;
+ gpgme_user_id_t tmp_uid;
+ /* Something new is available. */
+ int key_cond;
+ struct key_queue_item_s *key_queue;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+ struct key_queue_item_s *key = opd->key_queue;
+
+ if (opd->tmp_key)
+ gpgme_key_unref (opd->tmp_key);
+ if (opd->tmp_uid)
+ free (opd->tmp_uid);
+ while (key)
+ {
+ struct key_queue_item_s *next = key->next;
+
+ gpgme_key_unref (key->key);
+ key = next;
+ }
+}
+
+
+gpgme_keylist_result_t
+gpgme_op_keylist_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+static gpgme_error_t
+keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_TRUNCATED:
+ opd->result.truncated = 1;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static void
+set_subkey_trust_info (gpgme_subkey_t subkey, const char *src)
+{
+ while (*src && !isdigit (*src))
+ {
+ switch (*src)
+ {
+ case 'e':
+ subkey->expired = 1;
+ break;
+
+ case 'r':
+ subkey->revoked = 1;
+ break;
+
+ case 'd':
+ /* Note that gpg 1.3 won't print that anymore but only uses
+ the capabilities field. */
+ subkey->disabled = 1;
+ break;
+
+ case 'i':
+ subkey->invalid = 1;
+ break;
+ }
+ src++;
+ }
+}
+
+
+static void
+set_mainkey_trust_info (gpgme_key_t key, const char *src)
+{
+ /* First set the trust info of the main key (the first subkey). */
+ set_subkey_trust_info (key->subkeys, src);
+
+ /* Now set the summarized trust info. */
+ while (*src && !isdigit (*src))
+ {
+ switch (*src)
+ {
+ case 'e':
+ key->expired = 1;
+ break;
+
+ case 'r':
+ key->revoked = 1;
+ break;
+
+ case 'd':
+ /* Note that gpg 1.3 won't print that anymore but only uses
+ the capabilities field. */
+ key->disabled = 1;
+ break;
+
+ case 'i':
+ key->invalid = 1;
+ break;
+ }
+ src++;
+ }
+}
+
+
+static void
+set_userid_flags (gpgme_key_t key, const char *src)
+{
+ gpgme_user_id_t uid = key->_last_uid;
+
+ assert (uid);
+ /* Look at letters and stop at the first digit. */
+ while (*src && !isdigit (*src))
+ {
+ switch (*src)
+ {
+ case 'r':
+ uid->revoked = 1;
+ break;
+
+ case 'i':
+ uid->invalid = 1;
+ break;
+
+ case 'n':
+ uid->validity = GPGME_VALIDITY_NEVER;
+ break;
+
+ case 'm':
+ uid->validity = GPGME_VALIDITY_MARGINAL;
+ break;
+
+ case 'f':
+ uid->validity = GPGME_VALIDITY_FULL;
+ break;
+
+ case 'u':
+ uid->validity = GPGME_VALIDITY_ULTIMATE;
+ break;
+ }
+ src++;
+ }
+}
+
+
+static void
+set_subkey_capability (gpgme_subkey_t subkey, const char *src)
+{
+ while (*src)
+ {
+ switch (*src)
+ {
+ case 'e':
+ subkey->can_encrypt = 1;
+ break;
+
+ case 's':
+ subkey->can_sign = 1;
+ break;
+
+ case 'c':
+ subkey->can_certify = 1;
+ break;
+
+ case 'a':
+ subkey->can_authenticate = 1;
+ break;
+
+ case 'd':
+ subkey->disabled = 1;
+ break;
+ }
+ src++;
+ }
+}
+
+
+static void
+set_mainkey_capability (gpgme_key_t key, const char *src)
+{
+ /* First set the capabilities of the main key (the first subkey). */
+ set_subkey_capability (key->subkeys, src);
+
+ while (*src)
+ {
+ switch (*src)
+ {
+ case 'd':
+ case 'D':
+ /* Note, that this flag is also set using the key validity
+ field for backward compatibility with gpg 1.2. We use d
+ and D, so that a future gpg version will be able to
+ disable certain subkeys. Currently it is expected that
+ gpg sets this for the primary key. */
+ key->disabled = 1;
+ break;
+
+ case 'e':
+ case 'E':
+ key->can_encrypt = 1;
+ break;
+
+ case 's':
+ case 'S':
+ key->can_sign = 1;
+ break;
+
+ case 'c':
+ case 'C':
+ key->can_certify = 1;
+ break;
+
+ case 'a':
+ case 'A':
+ key->can_authenticate = 1;
+ break;
+ }
+ src++;
+ }
+}
+
+
+static void
+set_ownertrust (gpgme_key_t key, const char *src)
+{
+ /* Look at letters and stop at the first digit. */
+ while (*src && !isdigit (*src))
+ {
+ switch (*src)
+ {
+ case 'n':
+ key->owner_trust = GPGME_VALIDITY_NEVER;
+ break;
+
+ case 'm':
+ key->owner_trust = GPGME_VALIDITY_MARGINAL;
+ break;
+
+ case 'f':
+ key->owner_trust = GPGME_VALIDITY_FULL;
+ break;
+
+ case 'u':
+ key->owner_trust = GPGME_VALIDITY_ULTIMATE;
+ break;
+
+ default:
+ key->owner_trust = GPGME_VALIDITY_UNKNOWN;
+ break;
+ }
+ src++;
+ }
+}
+
+
+/* We have read an entire key into tmp_key and should now finish it.
+ It is assumed that this releases tmp_key. */
+static void
+finish_key (gpgme_ctx_t ctx, op_data_t opd)
+{
+ gpgme_key_t key = opd->tmp_key;
+
+ opd->tmp_key = NULL;
+ opd->tmp_uid = NULL;
+
+ if (key)
+ _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
+}
+
+
+/* Note: We are allowed to modify LINE. */
+static gpgme_error_t
+keylist_colon_handler (void *priv, char *line)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ enum
+ {
+ RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR,
+ RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV
+ }
+ rectype = RT_NONE;
+#define NR_FIELDS 13
+ char *field[NR_FIELDS];
+ int fields = 0;
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+ gpgme_key_t key;
+ gpgme_subkey_t subkey = NULL;
+ gpgme_key_sig_t keysig = NULL;
+
+ DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
+ ctx, key, line ? line : "(null)");
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ key = opd->tmp_key;
+
+ if (!line)
+ {
+ /* End Of File. */
+ finish_key (ctx, opd);
+ return 0;
+ }
+
+ while (line && fields < NR_FIELDS)
+ {
+ field[fields++] = line;
+ line = strchr (line, ':');
+ if (line)
+ *(line++) = '\0';
+ }
+
+ if (!strcmp (field[0], "sig"))
+ rectype = RT_SIG;
+ else if (!strcmp (field[0], "rev"))
+ rectype = RT_REV;
+ else if (!strcmp (field[0], "pub"))
+ rectype = RT_PUB;
+ else if (!strcmp (field[0], "sec"))
+ rectype = RT_SEC;
+ else if (!strcmp (field[0], "crt"))
+ rectype = RT_CRT;
+ else if (!strcmp (field[0], "crs"))
+ rectype = RT_CRS;
+ else if (!strcmp (field[0], "fpr") && key)
+ rectype = RT_FPR;
+ else if (!strcmp (field[0], "uid") && key)
+ rectype = RT_UID;
+ else if (!strcmp (field[0], "sub") && key)
+ rectype = RT_SUB;
+ else if (!strcmp (field[0], "ssb") && key)
+ rectype = RT_SSB;
+ else
+ rectype = RT_NONE;
+
+ /* Only look at signatures immediately following a user ID. For
+ this, clear the user ID pointer when encountering anything but a
+ signature. */
+ if (rectype != RT_SIG && rectype != RT_REV)
+ opd->tmp_uid = NULL;
+
+ switch (rectype)
+ {
+ case RT_PUB:
+ case RT_SEC:
+ case RT_CRT:
+ case RT_CRS:
+ /* Start a new keyblock. */
+ err = _gpgme_key_new (&key);
+ if (err)
+ return err;
+ key->keylist_mode = ctx->keylist_mode;
+ err = _gpgme_key_add_subkey (key, &subkey);
+ if (err)
+ {
+ gpgme_key_unref (key);
+ return err;
+ }
+
+ if (rectype == RT_SEC || rectype == RT_CRS)
+ key->secret = 1;
+ if (rectype == RT_CRT || rectype == RT_CRS)
+ key->protocol = GPGME_PROTOCOL_CMS;
+ finish_key (ctx, opd);
+ opd->tmp_key = key;
+
+ /* Field 2 has the trust info. */
+ if (fields >= 2)
+ set_mainkey_trust_info (key, field[1]);
+
+ /* Field 3 has the key length. */
+ if (fields >= 3)
+ {
+ int i = atoi (field[2]);
+ /* Ignore invalid values. */
+ if (i > 1)
+ subkey->length = i;
+ }
+
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ subkey->pubkey_algo = i;
+ }
+
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
+ strcpy (subkey->_keyid, field[4]);
+
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
+
+ /* Field 8 has the X.509 serial number. */
+ if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS))
+ {
+ key->issuer_serial = strdup (field[7]);
+ if (!key->issuer_serial)
+ return gpg_error_from_errno (errno);
+ }
+
+ /* Field 9 has the ownertrust. */
+ if (fields >= 9)
+ set_ownertrust (key, field[8]);
+
+ /* Field 10 is not used for gpg due to --fixed-list-mode option
+ but GPGSM stores the issuer name. */
+ if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS))
+ if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0))
+ return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
+
+ /* Field 11 has the signature class. */
+
+ /* Field 12 has the capabilities. */
+ if (fields >= 12)
+ set_mainkey_capability (key, field[11]);
+ break;
+
+ case RT_SUB:
+ case RT_SSB:
+ /* Start a new subkey. */
+ err = _gpgme_key_add_subkey (key, &subkey);
+ if (err)
+ return err;
+
+ if (rectype == RT_SSB)
+ subkey->secret = 1;
+
+ /* Field 2 has the trust info. */
+ if (fields >= 2)
+ set_subkey_trust_info (subkey, field[1]);
+
+ /* Field 3 has the key length. */
+ if (fields >= 3)
+ {
+ int i = atoi (field[2]);
+ /* Ignore invalid values. */
+ if (i > 1)
+ subkey->length = i;
+ }
+
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ subkey->pubkey_algo = i;
+ }
+
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1)
+ strcpy (subkey->_keyid, field[4]);
+
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ subkey->expires = _gpgme_parse_timestamp (field[6], NULL);
+
+ /* Field 8 is reserved (LID). */
+ /* Field 9 has the ownertrust. */
+ /* Field 10, the user ID, is n/a for a subkey. */
+
+ /* Field 11 has the signature class. */
+
+ /* Field 12 has the capabilities. */
+ if (fields >= 12)
+ set_subkey_capability (subkey, field[11]);
+ break;
+
+ case RT_UID:
+ /* Field 2 has the trust info, and field 10 has the user ID. */
+ if (fields >= 10)
+ {
+ if (_gpgme_key_append_name (key, field[9]))
+ return gpg_error_from_errno (GPG_ERR_ENOMEM); /* FIXME */
+ else
+ {
+ if (field[1])
+ set_userid_flags (key, field[1]);
+ opd->tmp_uid = key->_last_uid;
+ }
+ }
+ break;
+
+ case RT_FPR:
+ /* Field 10 has the fingerprint (take only the first one). */
+ if (fields >= 10 && !key->subkeys->fpr && field[9] && *field[9])
+ {
+ key->subkeys->fpr = strdup (field[9]);
+ if (!key->subkeys->fpr)
+ return gpg_error_from_errno (errno);
+ }
+
+ /* Field 13 has the gpgsm chain ID (take only the first one). */
+ if (fields >= 13 && !key->chain_id && *field[12])
+ {
+ key->chain_id = strdup (field[12]);
+ if (!key->chain_id)
+ return gpg_error_from_errno (errno);
+ }
+ break;
+
+ case RT_SIG:
+ case RT_REV:
+ if (!opd->tmp_uid)
+ return 0;
+
+ /* Start a new (revoked) signature. */
+ assert (opd->tmp_uid == key->_last_uid);
+ keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL);
+ if (!keysig)
+ return gpg_error (GPG_ERR_ENOMEM); /* FIXME */
+
+ /* Field 2 has the calculated trust ('!', '-', '?', '%'). */
+ if (fields >= 2)
+ switch (field[1][0])
+ {
+ case '!':
+ keysig->status = gpg_error (GPG_ERR_NO_ERROR);
+ break;
+
+ case '-':
+ keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
+ break;
+
+ case '?':
+ keysig->status = gpg_error (GPG_ERR_NO_PUBKEY);
+ break;
+
+ case '%':
+ keysig->status = gpg_error (GPG_ERR_GENERAL);
+ break;
+
+ default:
+ keysig->status = gpg_error (GPG_ERR_NO_ERROR);
+ break;
+ }
+
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ keysig->pubkey_algo = i;
+ }
+
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1)
+ strcpy (keysig->_keyid, field[4]);
+
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ keysig->expires = _gpgme_parse_timestamp (field[6], NULL);
+
+ /* Field 11 has the signature class (eg, 0x30 means revoked). */
+ if (fields >= 11)
+ if (field[10][0] && field[10][1])
+ {
+ int sig_class = _gpgme_hextobyte (field[10]);
+ if (sig_class >= 0)
+ {
+ keysig->sig_class = sig_class;
+ keysig->class = keysig->sig_class;
+ if (sig_class == 0x30)
+ keysig->revoked = 1;
+ }
+ if (field[10][2] == 'x')
+ keysig->exportable = 1;
+ }
+ break;
+
+ case RT_NONE:
+ /* Unknown record. */
+ break;
+ }
+ return 0;
+}
+
+
+void
+_gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
+{
+ gpgme_error_t err;
+ gpgme_ctx_t ctx = (gpgme_ctx_t) data;
+ gpgme_key_t key = (gpgme_key_t) type_data;
+ void *hook;
+ op_data_t opd;
+ struct key_queue_item_s *q, *q2;
+
+ assert (type == GPGME_EVENT_NEXT_KEY);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return;
+
+ q = malloc (sizeof *q);
+ if (!q)
+ {
+ gpgme_key_unref (key);
+ /* FIXME return GPGME_Out_Of_Core; */
+ return;
+ }
+ q->key = key;
+ q->next = NULL;
+ /* FIXME: Use a tail pointer? */
+ if (!(q2 = opd->key_queue))
+ opd->key_queue = q;
+ else
+ {
+ for (; q2->next; q2 = q2->next)
+ ;
+ q2->next = q;
+ }
+ opd->key_cond = 1;
+}
+
+
+/* Start a keylist operation within CTX, searching for keys which
+ match PATTERN. If SECRET_ONLY is true, only secret keys are
+ returned. */
+gpgme_error_t
+gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, 2);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
+
+ err = _gpgme_engine_set_colon_line_handler (ctx->engine,
+ keylist_colon_handler, ctx);
+ if (err)
+ return err;
+
+ return _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
+ ctx->keylist_mode);
+}
+
+
+/* Start a keylist operation within CTX, searching for keys which
+ match PATTERN. If SECRET_ONLY is true, only secret keys are
+ returned. */
+gpgme_error_t
+gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
+ int secret_only, int reserved)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_reset (ctx, 2);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx);
+ err = _gpgme_engine_set_colon_line_handler (ctx->engine,
+ keylist_colon_handler, ctx);
+ if (err)
+ return err;
+
+ return _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
+ reserved, ctx->keylist_mode);
+}
+
+
+/* Return the next key from the keylist in R_KEY. */
+gpgme_error_t
+gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
+{
+ gpgme_error_t err;
+ struct key_queue_item_s *queue_item;
+ void *hook;
+ op_data_t opd;
+
+ if (!ctx || !r_key)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ *r_key = NULL;
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ if (!opd->key_queue)
+ {
+ err = _gpgme_wait_on_condition (ctx, &opd->key_cond);
+ if (err)
+ return err;
+
+ if (!opd->key_cond)
+ return gpg_error (GPG_ERR_EOF);
+
+ opd->key_cond = 0;
+ assert (opd->key_queue);
+ }
+ queue_item = opd->key_queue;
+ opd->key_queue = queue_item->next;
+ if (!opd->key_queue)
+ opd->key_cond = 0;
+
+ *r_key = queue_item->key;
+ free (queue_item);
+ return 0;
+}
+
+
+/* Terminate a pending keylist operation within CTX. */
+gpgme_error_t
+gpgme_op_keylist_end (gpgme_ctx_t ctx)
+{
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ return 0;
+}
+
+
+/* Get the key with the fingerprint FPR from the crypto backend. If
+ SECRET is true, get the secret key. */
+gpgme_error_t
+gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key,
+ int secret)
+{
+ gpgme_ctx_t listctx;
+ gpgme_error_t err;
+ gpgme_key_t key;
+
+ if (!ctx || !r_key || !fpr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (strlen (fpr) < 16) /* We have at least a key ID. */
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* FIXME: We use our own context because we have to avoid the user's
+ I/O callback handlers. */
+ err = gpgme_new (&listctx);
+ if (err)
+ return err;
+ gpgme_set_protocol (listctx, gpgme_get_protocol (ctx));
+ gpgme_set_keylist_mode (listctx, ctx->keylist_mode);
+ err = gpgme_op_keylist_start (listctx, fpr, secret);
+ if (!err)
+ err = gpgme_op_keylist_next (listctx, r_key);
+ if (!err)
+ {
+ err = gpgme_op_keylist_next (listctx, &key);
+ if (gpgme_err_code (err) == GPG_ERR_EOF)
+ err = gpg_error (GPG_ERR_NO_ERROR);
+ else
+ {
+ if (!err)
+ {
+ gpgme_key_unref (key);
+ err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+ }
+ gpgme_key_unref (*r_key);
+ }
+ }
+ gpgme_release (listctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/libgpgme.vers b/branches/gpgme-1-0-branch/gpgme/libgpgme.vers
new file mode 100644
index 00000000..9bef503c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/libgpgme.vers
@@ -0,0 +1,146 @@
+# libgpgme.vers - List of symbols to export.
+# Copyright (C) 2002, 2004 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 Lesser general Public License as
+# published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser 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
+
+
+GPGME_1.0 {
+ global:
+ gpgme_check_version;
+ gpgme_get_engine_info;
+ gpgme_engine_check_version;
+
+ gpgme_err_code_from_errno;
+ gpgme_err_code_to_errno;
+ gpgme_err_make_from_errno;
+ gpgme_error_from_errno;
+ gpgme_strerror;
+ gpgme_strerror_r;
+ gpgme_strsource;
+
+ gpgme_data_get_encoding;
+ gpgme_data_new;
+ gpgme_data_new_from_cbs;
+ gpgme_data_new_from_fd;
+ gpgme_data_new_from_file;
+ gpgme_data_new_from_filepart;
+ gpgme_data_new_from_mem;
+ gpgme_data_new_from_stream;
+ gpgme_data_read;
+ gpgme_data_release;
+ gpgme_data_release_and_get_mem;
+ gpgme_data_seek;
+ gpgme_data_set_encoding;
+ gpgme_data_write;
+
+ gpgme_get_protocol_name;
+ gpgme_hash_algo_name;
+ gpgme_pubkey_algo_name;
+
+ gpgme_new;
+ gpgme_get_armor;
+ gpgme_get_include_certs;
+ gpgme_get_io_cbs;
+ gpgme_get_keylist_mode;
+ gpgme_get_passphrase_cb;
+ gpgme_get_progress_cb;
+ gpgme_get_protocol;
+ gpgme_get_textmode;
+ gpgme_release;
+ gpgme_set_armor;
+ gpgme_set_include_certs;
+ gpgme_set_io_cbs;
+ gpgme_set_keylist_mode;
+ gpgme_set_locale;
+ gpgme_set_passphrase_cb;
+ gpgme_set_progress_cb;
+ gpgme_set_protocol;
+ gpgme_set_textmode;
+ gpgme_signers_add;
+ gpgme_signers_clear;
+ gpgme_signers_enum;
+
+ gpgme_key_ref;
+ gpgme_key_unref;
+ gpgme_key_release;
+
+ gpgme_trust_item_ref;
+ gpgme_trust_item_unref;
+
+ gpgme_cancel;
+ gpgme_op_card_edit;
+ gpgme_op_card_edit_start;
+ gpgme_op_decrypt;
+ gpgme_op_decrypt_result;
+ gpgme_op_decrypt_start;
+ gpgme_op_decrypt_verify;
+ gpgme_op_decrypt_verify_start;
+ gpgme_op_delete;
+ gpgme_op_delete_start;
+ gpgme_op_edit;
+ gpgme_op_edit_start;
+ gpgme_op_encrypt;
+ gpgme_op_encrypt_result;
+ gpgme_op_encrypt_sign;
+ gpgme_op_encrypt_sign_start;
+ gpgme_op_encrypt_start;
+ gpgme_op_export;
+ gpgme_op_export_ext;
+ gpgme_op_export_ext_start;
+ gpgme_op_export_start;
+ gpgme_op_genkey;
+ gpgme_op_genkey_result;
+ gpgme_op_genkey_start;
+ gpgme_get_key;
+ gpgme_op_import;
+ gpgme_op_import_result;
+ gpgme_op_import_start;
+ gpgme_op_keylist_end;
+ gpgme_op_keylist_ext_start;
+ gpgme_op_keylist_next;
+ gpgme_op_keylist_result;
+ gpgme_op_keylist_start;
+ gpgme_op_sign;
+ gpgme_op_sign_result;
+ gpgme_op_sign_start;
+ gpgme_op_trustlist_end;
+ gpgme_op_trustlist_next;
+ gpgme_op_trustlist_start;
+ gpgme_op_verify;
+ gpgme_op_verify_result;
+ gpgme_op_verify_start;
+ gpgme_wait;
+
+ gpgme_data_new_with_read_cb;
+ gpgme_data_rewind;
+ gpgme_get_sig_status;
+ gpgme_get_sig_string_attr;
+ gpgme_get_sig_ulong_attr;
+ gpgme_get_sig_key;
+ gpgme_key_get_string_attr;
+ gpgme_key_get_ulong_attr;
+ gpgme_key_sig_get_string_attr;
+ gpgme_key_sig_get_ulong_attr;
+ gpgme_op_import_ext;
+ gpgme_trust_item_get_int_attr;
+ gpgme_trust_item_get_string_attr;
+ gpgme_trust_item_release;
+
+ local:
+ *;
+
+};
diff --git a/branches/gpgme-1-0-branch/gpgme/memrchr.c b/branches/gpgme-1-0-branch/gpgme/memrchr.c
new file mode 100644
index 00000000..41d38ae1
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/memrchr.c
@@ -0,0 +1,39 @@
+/* memrchr.c - Replacement for memrchr.
+ * Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+void *
+memrchr (const void *block, int c, size_t size)
+{
+ const unsigned char *p = block;
+
+ if (size)
+ {
+ for (p += size - 1; size; p--, size--)
+ if (*p == c)
+ return (void *)p;
+ }
+ return NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/mkstatus b/branches/gpgme-1-0-branch/gpgme/mkstatus
new file mode 100755
index 00000000..cc57969c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/mkstatus
@@ -0,0 +1,52 @@
+#!/bin/sh
+# mkstatus - Extract error strings from rungpg.h
+# and create a lookup table
+# Copyright (C) 2000 Werner Koch (dd9jn)
+# Copyright (C) 2001 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
+
+# resetting collate is important, so that the bsearch works properly
+LC_ALL=C
+LC_COLLATE=C
+export LC_ALL LC_COLLATE
+
+cat <<EOF
+/* Generated automatically by mkstatus */
+/* Do not edit! */
+
+struct status_table_s {
+ const char *name;
+ gpgme_status_code_t code;
+};
+
+static struct status_table_s status_table[] =
+{
+EOF
+
+awk '
+/GPGME_STATUS_ENTER/ { okay = 1 }
+!okay { next }
+/}/ { exit 0 }
+/GPGME_STATUS_[A-Za-z_]*/ { sub (/,/, "", $1); printf " { \"%s\", %s },\n", substr($1,14), $1 }
+' | sort
+
+cat <<EOF
+ {NULL, 0}
+};
+
+EOF
diff --git a/branches/gpgme-1-0-branch/gpgme/op-support.c b/branches/gpgme-1-0-branch/gpgme/op-support.c
new file mode 100644
index 00000000..be42e75c
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/op-support.c
@@ -0,0 +1,201 @@
+/* op-support.c
+ 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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+gpgme_error_t
+_gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook,
+ int size, void (*cleanup) (void *))
+{
+ struct ctx_op_data *data = ctx->op_data;
+ while (data && data->type != type)
+ data = data->next;
+ if (!data)
+ {
+ if (size < 0)
+ {
+ *hook = NULL;
+ return 0;
+ }
+
+ data = calloc (1, sizeof (struct ctx_op_data) + size);
+ if (!data)
+ return gpg_error_from_errno (errno);
+ data->next = ctx->op_data;
+ data->type = type;
+ data->cleanup = cleanup;
+ data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data));
+ ctx->op_data = data;
+ }
+ *hook = data->hook;
+ return 0;
+}
+
+
+/* type is: 0: asynchronous operation (use global or user event loop).
+ 1: synchronous operation (always use private event loop).
+ 2: asynchronous private operation (use private or user
+ event loop). */
+gpgme_error_t
+_gpgme_op_reset (gpgme_ctx_t ctx, int type)
+{
+ gpgme_error_t err = 0;
+ struct gpgme_io_cbs io_cbs;
+
+ _gpgme_release_result (ctx);
+
+ /* Create an engine object. */
+ if (ctx->engine)
+ {
+ _gpgme_engine_release (ctx->engine);
+ ctx->engine = NULL;
+ }
+ err = _gpgme_engine_new (ctx->protocol, &ctx->engine,
+ ctx->lc_ctype, ctx->lc_messages);
+ if (err)
+ return err;
+
+ if (type == 1 || (type == 2 && !ctx->io_cbs.add))
+ {
+ /* Use private event loop. */
+ io_cbs.add = _gpgme_add_io_cb;
+ io_cbs.add_priv = ctx;
+ io_cbs.remove = _gpgme_remove_io_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 = ctx;
+ io_cbs.remove = _gpgme_remove_io_cb;
+ io_cbs.event = _gpgme_wait_global_event_cb;
+ io_cbs.event_priv = ctx;
+ }
+ else
+ {
+ /* Use user event loop. */
+ 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);
+ return err;
+}
+
+
+gpgme_error_t
+_gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key)
+{
+ gpgme_invalid_key_t inv_key;
+ char *tail;
+ long int reason;
+
+ inv_key = malloc (sizeof (*inv_key));
+ if (!inv_key)
+ return gpg_error_from_errno (errno);
+ inv_key->next = NULL;
+ errno = 0;
+ reason = strtol (args, &tail, 0);
+ if (errno || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (inv_key);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+
+ switch (reason)
+ {
+ default:
+ case 0:
+ inv_key->reason = gpg_error (GPG_ERR_GENERAL);
+ break;
+
+ case 1:
+ inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY);
+ break;
+
+ case 2:
+ inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+ break;
+
+ case 3:
+ inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ break;
+
+ case 4:
+ inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED);
+ break;
+
+ case 5:
+ inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED);
+ break;
+
+ case 6:
+ inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN);
+ break;
+
+ case 7:
+ inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD);
+ break;
+
+ case 8:
+ inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH);
+ break;
+
+ case 9:
+ inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY);
+ break;
+
+ case 10:
+ inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED);
+ break;
+ }
+
+ while (*tail == ' ')
+ tail++;
+ if (*tail)
+ {
+ inv_key->fpr = strdup (tail);
+ if (!inv_key->fpr)
+ {
+ int saved_errno = errno;
+ free (inv_key);
+ return gpg_error_from_errno (saved_errno);
+ }
+ }
+ else
+ inv_key->fpr = NULL;
+
+ *key = inv_key;
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/ops.h b/branches/gpgme-1-0-branch/gpgme/ops.h
new file mode 100644
index 00000000..f01cc9a5
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/ops.h
@@ -0,0 +1,143 @@
+/* ops.h - Internal operation support.
+ 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 OPS_H
+#define OPS_H
+
+#include "gpgme.h"
+#include "context.h"
+
+
+/* From gpgme.c. */
+void _gpgme_release_result (gpgme_ctx_t ctx);
+
+
+/* From wait.c. */
+gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx);
+gpgme_error_t _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond);
+
+
+/* From data.c. */
+gpgme_error_t _gpgme_data_inbound_handler (void *opaque, int fd);
+gpgme_error_t _gpgme_data_outbound_handler (void *opaque, int fd);
+
+
+/* From op-support.c. */
+
+/* Find or create the op data object of type TYPE. */
+gpgme_error_t _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type,
+ void **hook, int size,
+ void (*cleanup) (void *));
+
+/* Prepare a new operation on CTX. */
+gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int synchronous);
+
+/* Parse the INV_RECP status line in ARGS and return the result in
+ KEY. */
+gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key);
+
+
+/* From verify.c. */
+gpgme_error_t _gpgme_op_verify_init_result (gpgme_ctx_t ctx);
+gpgme_error_t _gpgme_verify_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+
+
+/* From decrypt.c. */
+gpgme_error_t _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx);
+gpgme_error_t _gpgme_decrypt_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+
+
+/* From sign.c. */
+
+/* Create an initial op data object for signing. Needs to be called
+ once before calling _gpgme_sign_status_handler. */
+gpgme_error_t _gpgme_op_sign_init_result (gpgme_ctx_t ctx);
+
+/* Process a status line for signing operations. */
+gpgme_error_t _gpgme_sign_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+
+
+/* From encrypt.c. */
+
+/* Create an initial op data object for encrypt. Needs to be called
+ once before calling _gpgme_encrypt_status_handler. */
+gpgme_error_t _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx);
+
+/* Process a status line for encryption operations. */
+gpgme_error_t _gpgme_encrypt_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+
+
+/* From passphrase.c. */
+gpgme_error_t _gpgme_passphrase_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+gpgme_error_t _gpgme_passphrase_command_handler (void *opaque,
+ gpgme_status_code_t code,
+ const char *key, int fd);
+gpgme_error_t _gpgme_passphrase_command_handler_internal (void *opaque,
+ gpgme_status_code_t code,
+ const char *key, int fd,
+ int *processed);
+
+
+/* From progress.c. */
+gpgme_error_t _gpgme_progress_status_handler (void *priv,
+ gpgme_status_code_t code,
+ char *args);
+
+
+/* From key.c. */
+gpgme_error_t _gpgme_key_new (gpgme_key_t *r_key);
+gpgme_error_t _gpgme_key_add_subkey (gpgme_key_t key,
+ gpgme_subkey_t *r_subkey);
+gpgme_error_t _gpgme_key_append_name (gpgme_key_t key, char *src);
+gpgme_key_sig_t _gpgme_key_add_sig (gpgme_key_t key, char *src);
+
+
+/* From keylist.c. */
+void _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data);
+
+
+/* From trust-item.c. */
+
+/* Create a new trust item. */
+gpgme_error_t _gpgme_trust_item_new (gpgme_trust_item_t *r_item);
+
+
+/* From trustlist.c. */
+void _gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data);
+
+
+/*-- version.c --*/
+const char *_gpgme_compare_versions (const char *my_version,
+ const char *req_version);
+char *_gpgme_get_program_version (const char *const path);
+
+#endif /* OPS_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/passphrase.c b/branches/gpgme-1-0-branch/gpgme/passphrase.c
new file mode 100644
index 00000000..330246b7
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/passphrase.c
@@ -0,0 +1,160 @@
+/* passphrase.c - Passphrase callback.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ int no_passphrase;
+ char *uid_hint;
+ char *passphrase_info;
+ int bad_passphrase;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+
+ if (opd->passphrase_info)
+ free (opd->passphrase_info);
+ if (opd->uid_hint)
+ free (opd->uid_hint);
+}
+
+
+gpgme_error_t
+_gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code,
+ char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_USERID_HINT:
+ if (opd->uid_hint)
+ free (opd->uid_hint);
+ if (!(opd->uid_hint = strdup (args)))
+ return gpg_error_from_errno (errno);
+ break;
+
+ case GPGME_STATUS_BAD_PASSPHRASE:
+ opd->bad_passphrase++;
+ opd->no_passphrase = 0;
+ break;
+
+ case GPGME_STATUS_GOOD_PASSPHRASE:
+ opd->bad_passphrase = 0;
+ opd->no_passphrase = 0;
+ break;
+
+ case GPGME_STATUS_NEED_PASSPHRASE:
+ case GPGME_STATUS_NEED_PASSPHRASE_SYM:
+ if (opd->passphrase_info)
+ free (opd->passphrase_info);
+ opd->passphrase_info = strdup (args);
+ if (!opd->passphrase_info)
+ return gpg_error_from_errno (errno);
+ break;
+
+ case GPGME_STATUS_MISSING_PASSPHRASE:
+ opd->no_passphrase = 1;
+ break;
+
+ case GPGME_STATUS_EOF:
+ if (opd->no_passphrase || opd->bad_passphrase)
+ return gpg_error (GPG_ERR_BAD_PASSPHRASE);
+ break;
+
+ default:
+ /* Ignore all other codes. */
+ break;
+ }
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_passphrase_command_handler_internal (void *priv,
+ gpgme_status_code_t code,
+ const char *key, int fd,
+ int *processed)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ assert (ctx->passphrase_cb);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+
+ if (code == GPGME_STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter"))
+ {
+ if (processed)
+ *processed = 1;
+
+ err = ctx->passphrase_cb (ctx->passphrase_cb_value,
+ opd->uid_hint, opd->passphrase_info,
+ opd->bad_passphrase, fd);
+
+ /* Reset bad passphrase flag, in case it is correct now. */
+ opd->bad_passphrase = 0;
+
+ return err;
+ }
+
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code,
+ const char *key, int fd)
+{
+ return _gpgme_passphrase_command_handler_internal (priv, code, key, fd,
+ NULL);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/posix-io.c b/branches/gpgme-1-0-branch/gpgme/posix-io.c
new file mode 100644
index 00000000..5c9baaca
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/posix-io.c
@@ -0,0 +1,410 @@
+/* posix-io.c - Posix I/O functions
+ 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>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "util.h"
+#include "io.h"
+#include "sema.h"
+#include "ath.h"
+#include "debug.h"
+
+
+void
+_gpgme_io_subsystem_init (void)
+{
+ struct sigaction act;
+
+ sigaction (SIGPIPE, NULL, &act);
+ if (act.sa_handler == SIG_DFL)
+ {
+ act.sa_handler = SIG_IGN;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGPIPE, &act, NULL);
+ }
+}
+
+
+static struct
+{
+ void (*handler) (int,void*);
+ void *value;
+} notify_table[256];
+
+int
+_gpgme_io_read (int fd, void *buffer, size_t count)
+{
+ int nread;
+ int saved_errno;
+
+ DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
+ do
+ {
+ nread = _gpgme_ath_read (fd, buffer, count);
+ }
+ while (nread == -1 && errno == EINTR);
+ saved_errno = errno;
+ DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
+ if (nread > 0)
+ _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
+ errno = saved_errno;
+ return nread;
+}
+
+
+int
+_gpgme_io_write (int fd, const void *buffer, size_t count)
+{
+ int saved_errno;
+ int nwritten;
+
+ DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
+ _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
+ do
+ {
+ nwritten = _gpgme_ath_write (fd, buffer, count);
+ }
+ while (nwritten == -1 && errno == EINTR);
+ saved_errno = errno;
+ DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten);
+ errno = saved_errno;
+ return nwritten;
+}
+
+
+int
+_gpgme_io_pipe (int filedes[2], int inherit_idx)
+{
+ int saved_errno;
+ int err;
+
+ err = pipe (filedes);
+ if (err < 0)
+ return err;
+ /* FIXME: Should get the old flags first. */
+ err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
+ saved_errno = errno;
+ if (err < 0)
+ {
+ close (filedes[0]);
+ close (filedes[1]);
+ }
+ errno = saved_errno;
+ return err;
+}
+
+
+int
+_gpgme_io_close (int fd)
+{
+ if (fd == -1)
+ return -1;
+ /* First call the notify handler. */
+ DEBUG1 ("closing fd %d", fd);
+ if (fd >= 0 && fd < (int) DIM (notify_table))
+ {
+ if (notify_table[fd].handler)
+ {
+ notify_table[fd].handler (fd, notify_table[fd].value);
+ notify_table[fd].handler = NULL;
+ notify_table[fd].value = NULL;
+ }
+ }
+ /* Then do the close. */
+ return close (fd);
+}
+
+
+int
+_gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
+{
+ assert (fd != -1);
+
+ if (fd < 0 || fd >= (int) DIM (notify_table))
+ return -1;
+ DEBUG1 ("set notification for fd %d", fd);
+ notify_table[fd].handler = handler;
+ notify_table[fd].value = value;
+ return 0;
+}
+
+
+int
+_gpgme_io_set_nonblocking (int fd)
+{
+ int flags;
+
+ flags = fcntl (fd, F_GETFL, 0);
+ if (flags == -1)
+ return -1;
+ flags |= O_NONBLOCK;
+ return fcntl (fd, F_SETFL, flags);
+}
+
+
+/* Returns 0 on success, -1 on error. */
+int
+_gpgme_io_spawn (const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list)
+{
+ pid_t pid;
+ int i;
+ int status, signo;
+
+ pid = fork ();
+ if (pid == -1)
+ return -1;
+
+ if (!pid)
+ {
+ /* Intermediate child to prevent zombie processes. */
+ if ((pid = fork ()) == 0)
+ {
+ /* Child. */
+ int duped_stdin = 0;
+ int duped_stderr = 0;
+
+ /* First close all fds which will not be duped. */
+ for (i=0; fd_child_list[i].fd != -1; i++)
+ if (fd_child_list[i].dup_to == -1)
+ close (fd_child_list[i].fd);
+
+ /* And now dup and close the rest. */
+ for (i=0; fd_child_list[i].fd != -1; i++)
+ {
+ if (fd_child_list[i].dup_to != -1)
+ {
+ if (dup2 (fd_child_list[i].fd,
+ fd_child_list[i].dup_to) == -1)
+ {
+ DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
+ _exit (8);
+ }
+ if (fd_child_list[i].dup_to == 0)
+ duped_stdin=1;
+ if (fd_child_list[i].dup_to == 2)
+ duped_stderr=1;
+ close (fd_child_list[i].fd);
+ }
+ }
+
+ if (!duped_stdin || !duped_stderr)
+ {
+ int fd = open ("/dev/null", O_RDWR);
+ if (fd == -1)
+ {
+ DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno));
+ _exit (8);
+ }
+ /* Make sure that the process has a connected stdin. */
+ if (!duped_stdin)
+ {
+ if (dup2 (fd, 0) == -1)
+ {
+ DEBUG1("dup2(/dev/null, 0) failed: %s\n",
+ strerror (errno));
+ _exit (8);
+ }
+ }
+ if (!duped_stderr)
+ if (dup2 (fd, 2) == -1)
+ {
+ DEBUG1 ("dup2(dev/null, 2) failed: %s\n",
+ strerror (errno));
+ _exit (8);
+ }
+ close (fd);
+ }
+
+ execv ( path, argv );
+ /* Hmm: in that case we could write a special status code to the
+ status-pipe. */
+ DEBUG1 ("exec of `%s' failed\n", path);
+ _exit (8);
+ } /* End child. */
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+ }
+
+ _gpgme_io_waitpid (pid, 1, &status, &signo);
+ if (status)
+ return -1;
+
+ /* .dup_to is not used in the parent list. */
+ for (i = 0; fd_parent_list[i].fd != -1; i++)
+ _gpgme_io_close (fd_parent_list[i].fd);
+
+ return 0;
+}
+
+
+int
+_gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
+{
+ int status;
+
+ *r_status = 0;
+ *r_signal = 0;
+ if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
+ {
+ if (WIFSIGNALED (status))
+ {
+ *r_status = 4; /* Need some value here. */
+ *r_signal = WTERMSIG (status);
+ }
+ else if (WIFEXITED (status))
+ *r_status = WEXITSTATUS (status);
+ else
+ *r_status = 4; /* Oops. */
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+_gpgme_io_kill (int pid, int hard)
+{
+ return kill (pid, hard ? SIGKILL : SIGTERM);
+}
+
+
+/*
+ * Select on the list of fds.
+ * Returns: -1 = error
+ * 0 = timeout or nothing to select
+ * >0 = number of signaled fds
+ */
+int
+_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
+{
+ fd_set readfds;
+ fd_set writefds;
+ unsigned int i;
+ int any, max_fd, n, count;
+ struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */
+ void *dbg_help = NULL;
+
+ FD_ZERO (&readfds);
+ FD_ZERO (&writefds);
+ max_fd = 0;
+ if (nonblock)
+ timeout.tv_sec = 0;
+
+ DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
+ any = 0;
+ for (i = 0; i < nfds; i++)
+ {
+ if (fds[i].fd == -1)
+ continue;
+ if (fds[i].frozen)
+ DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
+ else if (fds[i].for_read)
+ {
+ assert (!FD_ISSET (fds[i].fd, &readfds));
+ FD_SET (fds[i].fd, &readfds);
+ if (fds[i].fd > max_fd)
+ max_fd = fds[i].fd;
+ DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd);
+ any = 1;
+ }
+ else if (fds[i].for_write)
+ {
+ assert (!FD_ISSET (fds[i].fd, &writefds));
+ FD_SET (fds[i].fd, &writefds);
+ if (fds[i].fd > max_fd)
+ max_fd = fds[i].fd;
+ DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd);
+ any = 1;
+ }
+ fds[i].signaled = 0;
+ }
+ DEBUG_END (dbg_help, "]");
+ if (!any)
+ return 0;
+
+ do
+ {
+ count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
+ &timeout);
+ }
+ while (count < 0 && errno == EINTR);
+ if (count < 0)
+ {
+ int saved_errno = errno;
+ DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
+ errno = saved_errno;
+ return -1; /* error */
+ }
+
+ DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
+ if (DEBUG_ENABLED (dbg_help))
+ {
+ for (i = 0; i <= max_fd; i++)
+ {
+ if (FD_ISSET (i, &readfds))
+ DEBUG_ADD1 (dbg_help, "r%d ", i);
+ if (FD_ISSET (i, &writefds))
+ DEBUG_ADD1 (dbg_help, "w%d ", i);
+ }
+ DEBUG_END (dbg_help, "]");
+ }
+
+ /* n is used to optimize it a little bit. */
+ for (n = count, i = 0; i < nfds && n; i++)
+ {
+ if (fds[i].fd == -1)
+ ;
+ else if (fds[i].for_read)
+ {
+ if (FD_ISSET (fds[i].fd, &readfds))
+ {
+ fds[i].signaled = 1;
+ n--;
+ }
+ }
+ else if (fds[i].for_write)
+ {
+ if (FD_ISSET (fds[i].fd, &writefds))
+ {
+ fds[i].signaled = 1;
+ n--;
+ }
+ }
+ }
+ return count;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/posix-sema.c b/branches/gpgme-1-0-branch/gpgme/posix-sema.c
new file mode 100644
index 00000000..45ca7289
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/posix-sema.c
@@ -0,0 +1,63 @@
+/* posix-sema.c
+ Copyright (C) 2001 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>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "util.h"
+#include "sema.h"
+#include "ath.h"
+
+void
+_gpgme_sema_subsystem_init ()
+{
+ /* FIXME: we should check that there is only one thread running */
+ _gpgme_ath_init ();
+}
+
+void
+_gpgme_sema_cs_enter (struct critsect_s *s)
+{
+ _gpgme_ath_mutex_lock (&s->private);
+}
+
+void
+_gpgme_sema_cs_leave (struct critsect_s *s)
+{
+ _gpgme_ath_mutex_unlock (&s->private);
+}
+
+void
+_gpgme_sema_cs_destroy (struct critsect_s *s)
+{
+ _gpgme_ath_mutex_destroy (&s->private);
+ s->private = NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/posix-util.c b/branches/gpgme-1-0-branch/gpgme/posix-util.c
new file mode 100644
index 00000000..47d4cca3
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/posix-util.c
@@ -0,0 +1,49 @@
+/* posix-util.c - Utility functions for Posix
+ Copyright (C) 2001 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>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h"
+
+const char *
+_gpgme_get_gpg_path (void)
+{
+#ifdef GPG_PATH
+ return GPG_PATH;
+#else
+ return NULL;
+#endif
+}
+
+const char *
+_gpgme_get_gpgsm_path (void)
+{
+#ifdef GPGSM_PATH
+ return GPGSM_PATH;
+#else
+ return NULL;
+#endif
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/progress.c b/branches/gpgme-1-0-branch/gpgme/progress.c
new file mode 100644
index 00000000..eb40421e
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/progress.c
@@ -0,0 +1,80 @@
+/* progress.c - status handler for progress status
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "context.h"
+
+
+gpgme_error_t
+_gpgme_progress_status_handler (void *priv, gpgme_status_code_t code,
+ char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ char *p;
+ char *args_cpy;
+ int type = 0;
+ int current = 0;
+ int total = 0;
+
+ if (code != GPGME_STATUS_PROGRESS || !*args || !ctx->progress_cb)
+ return 0;
+
+ args_cpy = strdup (args);
+ if (!args_cpy)
+ return gpg_error_from_errno (errno);
+
+ p = strchr (args_cpy, ' ');
+ if (p)
+ {
+ *p++ = 0;
+ if (*p)
+ {
+ type = *(unsigned char *)p;
+ p = strchr (p+1, ' ');
+ if (p)
+ {
+ *p++ = 0;
+ if (*p)
+ {
+ current = atoi (p);
+ p = strchr (p+1, ' ');
+ if (p)
+ {
+ *p++ = 0;
+ total = atoi (p);
+ }
+ }
+ }
+ }
+ }
+
+ if (type != 'X')
+ ctx->progress_cb (ctx->progress_cb_value, args_cpy, type, current, total);
+
+ free (args_cpy);
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/putc_unlocked.c b/branches/gpgme-1-0-branch/gpgme/putc_unlocked.c
new file mode 100644
index 00000000..02c64613
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/putc_unlocked.c
@@ -0,0 +1,31 @@
+/* putc_unlocked.c - Replacement for putc_unlocked.
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+
+int
+putc_unlocked (int c, FILE *stream)
+{
+ return putc (c, stream);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/rungpg.c b/branches/gpgme-1-0-branch/gpgme/rungpg.c
new file mode 100644
index 00000000..ce938c62
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/rungpg.c
@@ -0,0 +1,1688 @@
+/* rungpg.c - Gpg Engine.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "ops.h"
+#include "wait.h"
+#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
+#include "io.h"
+#include "sema.h"
+#include "debug.h"
+
+#include "status-table.h"
+#include "engine-backend.h"
+
+
+/* This type is used to build a list of gpg arguments and data
+ sources/sinks. */
+struct arg_and_data_s
+{
+ struct arg_and_data_s *next;
+ gpgme_data_t data; /* If this is not NULL, use arg below. */
+ int inbound; /* True if this is used for reading from gpg. */
+ int dup_to;
+ int print_fd; /* Print the fd number and not the special form of it. */
+ char arg[1]; /* Used if data above is not used. */
+};
+
+
+struct fd_data_map_s
+{
+ gpgme_data_t data;
+ int inbound; /* true if this is used for reading from gpg */
+ int dup_to;
+ int fd; /* the fd to use */
+ int peer_fd; /* the outher side of the pipe */
+ void *tag;
+};
+
+
+struct engine_gpg
+{
+ struct arg_and_data_s *arglist;
+ struct arg_and_data_s **argtail;
+
+ struct
+ {
+ int fd[2];
+ size_t bufsize;
+ char *buffer;
+ size_t readpos;
+ int eof;
+ engine_status_handler_t fnc;
+ void *fnc_value;
+ void *tag;
+ } status;
+
+ /* This is a kludge - see the comment at colon_line_handler. */
+ struct
+ {
+ int fd[2];
+ size_t bufsize;
+ char *buffer;
+ size_t readpos;
+ int eof;
+ engine_colon_line_handler_t fnc; /* this indicate use of this structrue */
+ void *fnc_value;
+ void *tag;
+ } colon;
+
+ char **argv;
+ struct fd_data_map_s *fd_data_map;
+
+ /* stuff needed for interactive (command) mode */
+ struct
+ {
+ int used;
+ int fd;
+ void *cb_data;
+ int idx; /* Index in fd_data_map */
+ gpgme_status_code_t code; /* last code */
+ char *keyword; /* what has been requested (malloced) */
+ engine_command_handler_t fnc;
+ void *fnc_value;
+ /* The kludges never end. This is used to couple command handlers
+ with output data in edit key mode. */
+ gpgme_data_t linked_data;
+ int linked_idx;
+ } cmd;
+
+ struct gpgme_io_cbs io_cbs;
+};
+
+typedef struct engine_gpg *engine_gpg_t;
+
+
+static void
+gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
+{
+ engine_gpg_t gpg = engine;
+
+ if (gpg->io_cbs.event)
+ (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
+}
+
+
+static void
+close_notify_handler (int fd, void *opaque)
+{
+ engine_gpg_t gpg = opaque;
+ assert (fd != -1);
+
+ if (gpg->status.fd[0] == fd)
+ {
+ if (gpg->status.tag)
+ (*gpg->io_cbs.remove) (gpg->status.tag);
+ gpg->status.fd[0] = -1;
+ }
+ else if (gpg->status.fd[1] == fd)
+ gpg->status.fd[1] = -1;
+ else if (gpg->colon.fd[0] == fd)
+ {
+ if (gpg->colon.tag)
+ (*gpg->io_cbs.remove) (gpg->colon.tag);
+ gpg->colon.fd[0] = -1;
+ }
+ else if (gpg->colon.fd[1] == fd)
+ gpg->colon.fd[1] = -1;
+ else if (gpg->fd_data_map)
+ {
+ int i;
+
+ for (i = 0; gpg->fd_data_map[i].data; i++)
+ {
+ if (gpg->fd_data_map[i].fd == fd)
+ {
+ if (gpg->fd_data_map[i].tag)
+ (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
+ gpg->fd_data_map[i].fd = -1;
+ break;
+ }
+ if (gpg->fd_data_map[i].peer_fd == fd)
+ {
+ gpg->fd_data_map[i].peer_fd = -1;
+ break;
+ }
+ }
+ }
+}
+
+static gpgme_error_t
+add_arg (engine_gpg_t gpg, const char *arg)
+{
+ struct arg_and_data_s *a;
+
+ assert (gpg);
+ assert (arg);
+
+ a = malloc (sizeof *a + strlen (arg));
+ if (!a)
+ return gpg_error_from_errno (errno);
+ a->next = NULL;
+ a->data = NULL;
+ a->dup_to = -1;
+ strcpy (a->arg, arg);
+ *gpg->argtail = a;
+ gpg->argtail = &a->next;
+ return 0;
+}
+
+static gpgme_error_t
+add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
+{
+ struct arg_and_data_s *a;
+
+ assert (gpg);
+ assert (data);
+
+ a = malloc (sizeof *a - 1);
+ if (!a)
+ return gpg_error_from_errno (errno);
+ a->next = NULL;
+ a->data = data;
+ a->inbound = inbound;
+ if (dup_to == -2)
+ {
+ a->print_fd = 1;
+ a->dup_to = -1;
+ }
+ else
+ {
+ a->print_fd = 0;
+ a->dup_to = dup_to;
+ }
+ *gpg->argtail = a;
+ gpg->argtail = &a->next;
+ return 0;
+}
+
+
+static const char *
+gpg_get_version (void)
+{
+ static const char *gpg_version;
+ DEFINE_STATIC_LOCK (gpg_version_lock);
+
+ LOCK (gpg_version_lock);
+ if (!gpg_version)
+ gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ());
+ UNLOCK (gpg_version_lock);
+ return gpg_version;
+}
+
+
+static const char *
+gpg_get_req_version (void)
+{
+ return NEED_GPG_VERSION;
+}
+
+
+static void
+free_argv (char **argv)
+{
+ int i;
+
+ for (i = 0; argv[i]; i++)
+ free (argv[i]);
+ free (argv);
+}
+
+
+static void
+free_fd_data_map (struct fd_data_map_s *fd_data_map)
+{
+ int i;
+
+ if (!fd_data_map)
+ return;
+
+ for (i = 0; fd_data_map[i].data; i++)
+ {
+ if (fd_data_map[i].fd != -1)
+ _gpgme_io_close (fd_data_map[i].fd);
+ if (fd_data_map[i].peer_fd != -1)
+ _gpgme_io_close (fd_data_map[i].peer_fd);
+ /* Don't release data because this is only a reference. */
+ }
+ free (fd_data_map);
+}
+
+
+static gpgme_error_t
+gpg_cancel (void *engine)
+{
+ engine_gpg_t gpg = engine;
+
+ if (!gpg)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (gpg->status.fd[0] != -1)
+ _gpgme_io_close (gpg->status.fd[0]);
+ if (gpg->status.fd[1] != -1)
+ _gpgme_io_close (gpg->status.fd[1]);
+ if (gpg->colon.fd[0] != -1)
+ _gpgme_io_close (gpg->colon.fd[0]);
+ if (gpg->colon.fd[1] != -1)
+ _gpgme_io_close (gpg->colon.fd[1]);
+ if (gpg->fd_data_map)
+ {
+ free_fd_data_map (gpg->fd_data_map);
+ gpg->fd_data_map = NULL;
+ }
+ if (gpg->cmd.fd != -1)
+ _gpgme_io_close (gpg->cmd.fd);
+
+ return 0;
+}
+
+static void
+gpg_release (void *engine)
+{
+ engine_gpg_t gpg = engine;
+
+ if (!gpg)
+ return;
+
+ gpg_cancel (engine);
+
+ while (gpg->arglist)
+ {
+ struct arg_and_data_s *next = gpg->arglist->next;
+
+ if (gpg->arglist)
+ free (gpg->arglist);
+ gpg->arglist = next;
+ }
+
+ if (gpg->status.buffer)
+ free (gpg->status.buffer);
+ if (gpg->colon.buffer)
+ free (gpg->colon.buffer);
+ if (gpg->argv)
+ free_argv (gpg->argv);
+ if (gpg->cmd.keyword)
+ free (gpg->cmd.keyword);
+
+ free (gpg);
+}
+
+
+static gpgme_error_t
+gpg_new (void **engine, const char *lc_ctype, const char *lc_messages)
+{
+ engine_gpg_t gpg;
+ gpgme_error_t rc = 0;
+
+ gpg = calloc (1, sizeof *gpg);
+ if (!gpg)
+ return gpg_error_from_errno (errno);
+
+ gpg->argtail = &gpg->arglist;
+ gpg->status.fd[0] = -1;
+ gpg->status.fd[1] = -1;
+ gpg->colon.fd[0] = -1;
+ gpg->colon.fd[1] = -1;
+ gpg->cmd.fd = -1;
+ gpg->cmd.idx = -1;
+ gpg->cmd.linked_data = NULL;
+ gpg->cmd.linked_idx = -1;
+
+ /* Allocate the read buffer for the status pipe. */
+ gpg->status.bufsize = 1024;
+ gpg->status.readpos = 0;
+ gpg->status.buffer = malloc (gpg->status.bufsize);
+ if (!gpg->status.buffer)
+ {
+ rc = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ /* In any case we need a status pipe - create it right here and
+ don't handle it with our generic gpgme_data_t mechanism. */
+ if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
+ {
+ rc = gpg_error_from_errno (errno);
+ goto leave;
+ }
+ if (_gpgme_io_set_close_notify (gpg->status.fd[0],
+ close_notify_handler, gpg)
+ || _gpgme_io_set_close_notify (gpg->status.fd[1],
+ close_notify_handler, gpg))
+ {
+ rc = gpg_error (GPG_ERR_GENERAL);
+ goto leave;
+ }
+ gpg->status.eof = 0;
+ rc = add_arg (gpg, "--status-fd");
+ if (rc)
+ goto leave;
+
+ {
+ char buf[25];
+ sprintf (buf, "%d", gpg->status.fd[1]);
+ rc = add_arg (gpg, buf);
+ if (rc)
+ goto leave;
+ }
+
+ rc = add_arg (gpg, "--no-tty");
+ if (!rc)
+ rc = add_arg (gpg, "--charset");
+ if (!rc)
+ rc = add_arg (gpg, "utf8");
+ if (!rc)
+ rc = add_arg (gpg, "--enable-progress-filter");
+
+ leave:
+ if (rc)
+ gpg_release (gpg);
+ else
+ *engine = gpg;
+ return rc;
+}
+
+
+/* Note, that the status_handler is allowed to modifiy the args
+ value. */
+static void
+gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
+ void *fnc_value)
+{
+ engine_gpg_t gpg = engine;
+
+ gpg->status.fnc = fnc;
+ gpg->status.fnc_value = fnc_value;
+}
+
+/* Kludge to process --with-colon output. */
+static gpgme_error_t
+gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
+ void *fnc_value)
+{
+ engine_gpg_t gpg = engine;
+
+ gpg->colon.bufsize = 1024;
+ gpg->colon.readpos = 0;
+ gpg->colon.buffer = malloc (gpg->colon.bufsize);
+ if (!gpg->colon.buffer)
+ return gpg_error_from_errno (errno);
+
+ if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
+ {
+ int saved_errno = errno;
+ free (gpg->colon.buffer);
+ gpg->colon.buffer = NULL;
+ return gpg_error_from_errno (saved_errno);
+ }
+ if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
+ || _gpgme_io_set_close_notify (gpg->colon.fd[1],
+ close_notify_handler, gpg))
+ return gpg_error (GPG_ERR_GENERAL);
+ gpg->colon.eof = 0;
+ gpg->colon.fnc = fnc;
+ gpg->colon.fnc_value = fnc_value;
+ return 0;
+}
+
+
+static gpgme_error_t
+command_handler (void *opaque, int fd)
+{
+ gpgme_error_t err;
+ engine_gpg_t gpg = (engine_gpg_t) opaque;
+
+ assert (gpg->cmd.used);
+ assert (gpg->cmd.code);
+ assert (gpg->cmd.fnc);
+
+ err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd);
+ if (err)
+ return err;
+
+ 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
+ this one. */
+ (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
+ gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
+ gpg->fd_data_map[gpg->cmd.idx].fd = -1;
+
+ return 0;
+}
+
+
+
+/* The Fnc will be called to get a value for one of the commands with
+ a key KEY. If the Code pssed to FNC is 0, the function may release
+ resources associated with the returned value from another call. To
+ match such a second call to a first call, the returned value from
+ the first call is passed as keyword. */
+static gpgme_error_t
+gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
+ void *fnc_value, gpgme_data_t linked_data)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t rc;
+
+ rc = add_arg (gpg, "--command-fd");
+ if (rc)
+ return rc;
+
+ /* This is a hack. We don't have a real data object. The only
+ thing that matters is that we use something unique, so we use the
+ address of the cmd structure in the gpg object. */
+ rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
+ if (rc)
+ return rc;
+
+ gpg->cmd.fnc = fnc;
+ gpg->cmd.cb_data = (void *) &gpg->cmd;
+ gpg->cmd.fnc_value = fnc_value;
+ gpg->cmd.linked_data = linked_data;
+ gpg->cmd.used = 1;
+ return 0;
+}
+
+
+static gpgme_error_t
+build_argv (engine_gpg_t gpg)
+{
+ gpgme_error_t err;
+ struct arg_and_data_s *a;
+ struct fd_data_map_s *fd_data_map;
+ size_t datac=0, argc=0;
+ char **argv;
+ int need_special = 0;
+ int use_agent = 0;
+ char *p;
+
+ /* We don't want to use the agent with a malformed environment
+ variable. This is only a very basic test but sufficient to make
+ our life in the regression tests easier. */
+ err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
+ if (err)
+ return err;
+ use_agent = (p && strchr (p, ':'));
+ if (p)
+ free (p);
+
+ if (gpg->argv)
+ {
+ free_argv (gpg->argv);
+ gpg->argv = NULL;
+ }
+ if (gpg->fd_data_map)
+ {
+ free_fd_data_map (gpg->fd_data_map);
+ gpg->fd_data_map = NULL;
+ }
+
+ argc++; /* For argv[0]. */
+ for (a = gpg->arglist; a; a = a->next)
+ {
+ argc++;
+ if (a->data)
+ {
+ /*fprintf (stderr, "build_argv: data\n" );*/
+ datac++;
+ if (a->dup_to == -1 && !a->print_fd)
+ need_special = 1;
+ }
+ else
+ {
+ /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
+ }
+ }
+ if (need_special)
+ argc++;
+ if (use_agent)
+ argc++;
+ if (!gpg->cmd.used)
+ argc++; /* --batch */
+ argc += 1; /* --no-sk-comment */
+
+ argv = calloc (argc + 1, sizeof *argv);
+ if (!argv)
+ return gpg_error_from_errno (errno);
+ fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
+ if (!fd_data_map)
+ {
+ int saved_errno = errno;
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+
+ argc = datac = 0;
+ argv[argc] = strdup ("gpg"); /* argv[0] */
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ if (need_special)
+ {
+ argv[argc] = strdup ("--enable-special-filenames");
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ }
+ if (use_agent)
+ {
+ argv[argc] = strdup ("--use-agent");
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ }
+ if (!gpg->cmd.used)
+ {
+ argv[argc] = strdup ("--batch");
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ }
+ argv[argc] = strdup ("--no-sk-comment");
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ for (a = gpg->arglist; a; a = a->next)
+ {
+ if (a->data)
+ {
+ /* Create a pipe to pass it down to gpg. */
+ fd_data_map[datac].inbound = a->inbound;
+
+ /* Create a pipe. */
+ {
+ int fds[2];
+
+ if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
+ == -1)
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error (saved_errno);
+ }
+ if (_gpgme_io_set_close_notify (fds[0],
+ close_notify_handler, gpg)
+ || _gpgme_io_set_close_notify (fds[1],
+ close_notify_handler,
+ gpg))
+ {
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+ /* If the data_type is FD, we have to do a dup2 here. */
+ if (fd_data_map[datac].inbound)
+ {
+ fd_data_map[datac].fd = fds[0];
+ fd_data_map[datac].peer_fd = fds[1];
+ }
+ else
+ {
+ fd_data_map[datac].fd = fds[1];
+ fd_data_map[datac].peer_fd = fds[0];
+ }
+ }
+
+ /* Hack to get hands on the fd later. */
+ if (gpg->cmd.used)
+ {
+ if (gpg->cmd.cb_data == a->data)
+ {
+ assert (gpg->cmd.idx == -1);
+ gpg->cmd.idx = datac;
+ }
+ else if (gpg->cmd.linked_data == a->data)
+ {
+ assert (gpg->cmd.linked_idx == -1);
+ gpg->cmd.linked_idx = datac;
+ }
+ }
+
+ fd_data_map[datac].data = a->data;
+ fd_data_map[datac].dup_to = a->dup_to;
+ if (a->dup_to == -1)
+ {
+ argv[argc] = malloc (25);
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ sprintf (argv[argc],
+ a->print_fd ? "%d" : "-&%d",
+ fd_data_map[datac].peer_fd);
+ argc++;
+ }
+ datac++;
+ }
+ else
+ {
+ argv[argc] = strdup (a->arg);
+ if (!argv[argc])
+ {
+ int saved_errno = errno;
+ free (fd_data_map);
+ free_argv (argv);
+ return gpg_error_from_errno (saved_errno);
+ }
+ argc++;
+ }
+ }
+
+ gpg->argv = argv;
+ gpg->fd_data_map = fd_data_map;
+ return 0;
+}
+
+
+static gpgme_error_t
+add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
+ void **tag)
+{
+ gpgme_error_t err;
+
+ err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
+ if (err)
+ return err;
+ if (!dir)
+ /* FIXME Kludge around poll() problem. */
+ err = _gpgme_io_set_nonblocking (fd);
+ return err;
+}
+
+
+static int
+status_cmp (const void *ap, const void *bp)
+{
+ const struct status_table_s *a = ap;
+ const struct status_table_s *b = bp;
+
+ return strcmp (a->name, b->name);
+}
+
+
+/* Handle the status output of GnuPG. This function does read entire
+ lines and passes them as C strings to the callback function (we can
+ use C Strings because the status output is always UTF-8 encoded).
+ Of course we have to buffer the lines to cope with long lines
+ e.g. with a large user ID. Note: We can optimize this to only cope
+ with status line code we know about and skip all other stuff
+ without buffering (i.e. without extending the buffer). */
+static gpgme_error_t
+read_status (engine_gpg_t gpg)
+{
+ char *p;
+ int nread;
+ size_t bufsize = gpg->status.bufsize;
+ char *buffer = gpg->status.buffer;
+ size_t readpos = gpg->status.readpos;
+
+ assert (buffer);
+ if (bufsize - readpos < 256)
+ {
+ /* Need more room for the read. */
+ bufsize += 1024;
+ buffer = realloc (buffer, bufsize);
+ if (!buffer)
+ return gpg_error_from_errno (errno);
+ }
+
+ nread = _gpgme_io_read (gpg->status.fd[0],
+ buffer + readpos, bufsize-readpos);
+ if (nread == -1)
+ return gpg_error_from_errno (errno);
+
+ if (!nread)
+ {
+ gpg->status.eof = 1;
+ if (gpg->status.fnc)
+ {
+ gpgme_error_t err;
+ err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
+ if (err)
+ return err;
+ }
+ return 0;
+ }
+
+ while (nread > 0)
+ {
+ for (p = buffer + readpos; nread; nread--, p++)
+ {
+ if (*p == '\n')
+ {
+ /* (we require that the last line is terminated by a LF) */
+ *p = 0;
+ if (!strncmp (buffer, "[GNUPG:] ", 9)
+ && buffer[9] >= 'A' && buffer[9] <= 'Z')
+ {
+ struct status_table_s t, *r;
+ char *rest;
+
+ rest = strchr (buffer + 9, ' ');
+ if (!rest)
+ rest = p; /* Set to an empty string. */
+ else
+ *rest++ = 0;
+
+ t.name = buffer+9;
+ /* (the status table has one extra element) */
+ r = bsearch (&t, status_table, DIM(status_table) - 1,
+ sizeof t, status_cmp);
+ if (r)
+ {
+ if (gpg->cmd.used
+ && (r->code == GPGME_STATUS_GET_BOOL
+ || r->code == GPGME_STATUS_GET_LINE
+ || r->code == GPGME_STATUS_GET_HIDDEN))
+ {
+ gpg->cmd.code = r->code;
+ if (gpg->cmd.keyword)
+ free (gpg->cmd.keyword);
+ gpg->cmd.keyword = strdup (rest);
+ if (!gpg->cmd.keyword)
+ return gpg_error_from_errno (errno);
+ /* This should be the last thing we have
+ received and the next thing will be that
+ the command handler does its action. */
+ if (nread > 1)
+ DEBUG0 ("ERROR, unexpected data in read_status");
+
+ add_io_cb (gpg, gpg->cmd.fd, 0,
+ command_handler, gpg,
+ &gpg->fd_data_map[gpg->cmd.idx].tag);
+ gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
+ gpg->cmd.fd = -1;
+ }
+ else if (gpg->status.fnc)
+ {
+ gpgme_error_t err;
+ err = gpg->status.fnc (gpg->status.fnc_value,
+ r->code, rest);
+ if (err)
+ return err;
+ }
+
+ if (r->code == GPGME_STATUS_END_STREAM)
+ {
+ if (gpg->cmd.used)
+ {
+ /* Before we can actually add the
+ command fd, we might have to flush
+ the linked output data pipe. */
+ if (gpg->cmd.linked_idx != -1
+ && gpg->fd_data_map[gpg->cmd.linked_idx].fd
+ != -1)
+ {
+ struct io_select_fd_s fds;
+ fds.fd =
+ gpg->fd_data_map[gpg->cmd.linked_idx].fd;
+ fds.for_read = 1;
+ fds.for_write = 0;
+ fds.frozen = 0;
+ fds.opaque = NULL;
+ do
+ {
+ fds.signaled = 0;
+ _gpgme_io_select (&fds, 1, 1);
+ if (fds.signaled)
+ _gpgme_data_inbound_handler
+ (gpg->cmd.linked_data, fds.fd);
+ }
+ while (fds.signaled);
+ }
+
+ /* XXX We must check if there are any
+ more fds active after removing this
+ one. */
+ (*gpg->io_cbs.remove)
+ (gpg->fd_data_map[gpg->cmd.idx].tag);
+ gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
+ gpg->fd_data_map[gpg->cmd.idx].fd = -1;
+ }
+ }
+ }
+ }
+ /* To reuse the buffer for the next line we have to
+ shift the remaining data to the buffer start and
+ restart the loop Hmmm: We can optimize this function
+ by looking forward in the buffer to see whether a
+ second complete line is available and in this case
+ avoid the memmove for this line. */
+ nread--; p++;
+ if (nread)
+ memmove (buffer, p, nread);
+ readpos = 0;
+ break; /* the for loop */
+ }
+ else
+ readpos++;
+ }
+ }
+
+ /* Update the gpg object. */
+ gpg->status.bufsize = bufsize;
+ gpg->status.buffer = buffer;
+ gpg->status.readpos = readpos;
+ return 0;
+}
+
+
+static gpgme_error_t
+status_handler (void *opaque, int fd)
+{
+ engine_gpg_t gpg = opaque;
+ int err;
+
+ assert (fd == gpg->status.fd[0]);
+ err = read_status (gpg);
+ if (err)
+ return err;
+ if (gpg->status.eof)
+ _gpgme_io_close (fd);
+ return 0;
+}
+
+
+static gpgme_error_t
+read_colon_line (engine_gpg_t gpg)
+{
+ char *p;
+ int nread;
+ size_t bufsize = gpg->colon.bufsize;
+ char *buffer = gpg->colon.buffer;
+ size_t readpos = gpg->colon.readpos;
+
+ assert (buffer);
+ if (bufsize - readpos < 256)
+ {
+ /* Need more room for the read. */
+ bufsize += 1024;
+ buffer = realloc (buffer, bufsize);
+ if (!buffer)
+ return gpg_error_from_errno (errno);
+ }
+
+ nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
+ if (nread == -1)
+ return gpg_error_from_errno (errno);
+
+ if (!nread)
+ {
+ gpg->colon.eof = 1;
+ assert (gpg->colon.fnc);
+ gpg->colon.fnc (gpg->colon.fnc_value, NULL);
+ return 0;
+ }
+
+ while (nread > 0)
+ {
+ for (p = buffer + readpos; nread; nread--, p++)
+ {
+ if ( *p == '\n' )
+ {
+ /* (we require that the last line is terminated by a LF)
+ and we skip empty lines. Note: we use UTF8 encoding
+ and escaping of special characters We require at
+ least one colon to cope with some other printed
+ information. */
+ *p = 0;
+ if (*buffer && strchr (buffer, ':'))
+ {
+ assert (gpg->colon.fnc);
+ gpg->colon.fnc (gpg->colon.fnc_value, buffer);
+ }
+
+ /* To reuse the buffer for the next line we have to
+ shift the remaining data to the buffer start and
+ restart the loop Hmmm: We can optimize this function
+ by looking forward in the buffer to see whether a
+ second complete line is available and in this case
+ avoid the memmove for this line. */
+ nread--; p++;
+ if (nread)
+ memmove (buffer, p, nread);
+ readpos = 0;
+ break; /* The for loop. */
+ }
+ else
+ readpos++;
+ }
+ }
+
+ /* Update the gpg object. */
+ gpg->colon.bufsize = bufsize;
+ gpg->colon.buffer = buffer;
+ gpg->colon.readpos = readpos;
+ return 0;
+}
+
+
+/* This colonline handler thing is not the clean way to do it. It
+ might be better to enhance the gpgme_data_t 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 gpgme_error_t
+colon_line_handler (void *opaque, int fd)
+{
+ engine_gpg_t gpg = opaque;
+ gpgme_error_t rc = 0;
+
+ assert (fd == gpg->colon.fd[0]);
+ rc = read_colon_line (gpg);
+ if (rc)
+ return rc;
+ if (gpg->colon.eof)
+ _gpgme_io_close (fd);
+ return 0;
+}
+
+
+static gpgme_error_t
+start (engine_gpg_t gpg)
+{
+ gpgme_error_t rc;
+ int saved_errno;
+ int i, n;
+ int status;
+ struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
+
+ if (!gpg)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (! _gpgme_get_gpg_path ())
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ rc = build_argv (gpg);
+ if (rc)
+ return rc;
+
+ n = 3; /* status_fd, colon_fd and end of list */
+ for (i = 0; gpg->fd_data_map[i].data; i++)
+ n++;
+ fd_child_list = calloc (n + n, sizeof *fd_child_list);
+ if (!fd_child_list)
+ return gpg_error_from_errno (errno);
+ fd_parent_list = fd_child_list + n;
+
+ /* build the fd list for the child */
+ n = 0;
+ if (gpg->colon.fnc)
+ {
+ fd_child_list[n].fd = gpg->colon.fd[1];
+ fd_child_list[n].dup_to = 1; /* dup to stdout */
+ n++;
+ }
+ for (i = 0; gpg->fd_data_map[i].data; i++)
+ {
+ if (gpg->fd_data_map[i].dup_to != -1)
+ {
+ fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
+ fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
+ n++;
+ }
+ }
+ fd_child_list[n].fd = -1;
+ fd_child_list[n].dup_to = -1;
+
+ /* Build the fd list for the parent. */
+ n = 0;
+ if (gpg->status.fd[1] != -1)
+ {
+ fd_parent_list[n].fd = gpg->status.fd[1];
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ }
+ if (gpg->colon.fd[1] != -1)
+ {
+ fd_parent_list[n].fd = gpg->colon.fd[1];
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ }
+ for (i = 0; gpg->fd_data_map[i].data; i++)
+ {
+ fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
+ fd_parent_list[n].dup_to = -1;
+ n++;
+ }
+ fd_parent_list[n].fd = -1;
+ fd_parent_list[n].dup_to = -1;
+
+ status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
+ gpg->argv, fd_child_list, fd_parent_list);
+ saved_errno = errno;
+ free (fd_child_list);
+ if (status == -1)
+ return gpg_error_from_errno (saved_errno);
+
+ /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
+
+ rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
+ &gpg->status.tag);
+ if (rc)
+ /* FIXME: kill the child */
+ return rc;
+
+ if (gpg->colon.fnc)
+ {
+ assert (gpg->colon.fd[0] != -1);
+ rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
+ &gpg->colon.tag);
+ if (rc)
+ /* FIXME: kill the child */
+ return rc;
+ }
+
+ for (i = 0; gpg->fd_data_map[i].data; i++)
+ {
+ if (gpg->cmd.used && i == gpg->cmd.idx)
+ {
+ /* Park the cmd fd. */
+ gpg->cmd.fd = gpg->fd_data_map[i].fd;
+ gpg->fd_data_map[i].fd = -1;
+ }
+ else
+ {
+ rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
+ gpg->fd_data_map[i].inbound,
+ gpg->fd_data_map[i].inbound
+ ? _gpgme_data_inbound_handler
+ : _gpgme_data_outbound_handler,
+ gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
+
+ if (rc)
+ /* FIXME: kill the child */
+ return rc;
+ }
+ }
+
+ (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL);
+
+ /* fixme: check what data we can release here */
+ return 0;
+}
+
+
+static gpgme_error_t
+gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--decrypt");
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_arg (gpg, "--output");
+ if (!err)
+ err = add_arg (gpg, "-");
+ if (!err)
+ err = add_data (gpg, plain, 1, 1);
+ if (!err)
+ err = add_data (gpg, ciph, 0, 0);
+
+ if (!err)
+ start (gpg);
+ return err;
+}
+
+static gpgme_error_t
+gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
+ : "--delete-key");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ {
+ if (!key->subkeys || !key->subkeys->fpr)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ else
+ err = add_arg (gpg, key->subkeys->fpr);
+ }
+
+ if (!err)
+ start (gpg);
+ return err;
+}
+
+
+static gpgme_error_t
+append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
+{
+ gpgme_error_t err = 0;
+ int i;
+ gpgme_key_t key;
+
+ for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
+ {
+ const char *s = key->subkeys ? key->subkeys->keyid : NULL;
+ if (s)
+ {
+ if (!err)
+ err = add_arg (gpg, "-u");
+ if (!err)
+ err = add_arg (gpg, s);
+ }
+ gpgme_key_unref (key);
+ if (err) break;
+ }
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
+ gpgme_ctx_t ctx /* FIXME */)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--with-colons");
+ if (!err)
+ err = append_args_from_signers (gpg, ctx);
+ if (!err)
+ err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
+ if (!err)
+ err = add_data (gpg, out, 1, 1);
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ {
+ const char *s = key->subkeys ? key->subkeys->fpr : NULL;
+ if (!s)
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ else
+ err = add_arg (gpg, s);
+ }
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
+{
+ gpgme_error_t err = 0;
+ int i = 0;
+
+ while (recp[i])
+ {
+ if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ if (!err)
+ err = add_arg (gpg, "-r");
+ if (!err)
+ err = add_arg (gpg, recp[i]->subkeys->fpr);
+ if (err)
+ break;
+ i++;
+ }
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
+ gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+ int symmetric = !recp;
+
+ err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
+
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+
+ if (!symmetric)
+ {
+ /* If we know that all recipients are valid (full or ultimate trust)
+ we can suppress further checks. */
+ if (!err && !symmetric && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
+ err = add_arg (gpg, "--always-trust");
+
+ if (!err)
+ err = append_args_from_recipients (gpg, recp);
+ }
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_arg (gpg, "--output");
+ if (!err)
+ err = add_arg (gpg, "-");
+ if (!err)
+ err = add_data (gpg, ciph, 1, 1);
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, plain, 0, 0);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
+ gpgme_encrypt_flags_t flags, gpgme_data_t plain,
+ gpgme_data_t ciph, int use_armor,
+ gpgme_ctx_t ctx /* FIXME */)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--encrypt");
+ if (!err)
+ err = add_arg (gpg, "--sign");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+
+ /* If we know that all recipients are valid (full or ultimate trust)
+ we can suppress further checks. */
+ if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
+ err = add_arg (gpg, "--always-trust");
+
+ if (!err)
+ err = append_args_from_recipients (gpg, recp);
+
+ if (!err)
+ err = append_args_from_signers (gpg, ctx);
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_arg (gpg, "--output");
+ if (!err)
+ err = add_arg (gpg, "-");
+ if (!err)
+ err = add_data (gpg, ciph, 1, 1);
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, plain, 0, 0);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_export (void *engine, const char *pattern, unsigned int reserved,
+ gpgme_data_t keydata, int use_armor)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ if (reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = add_arg (gpg, "--export");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err)
+ err = add_data (gpg, keydata, 1, 1);
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (!err && pattern && *pattern)
+ err = add_arg (gpg, pattern);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved,
+ gpgme_data_t keydata, int use_armor)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ if (reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = add_arg (gpg, "--export");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err)
+ err = add_data (gpg, keydata, 1, 1);
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (pattern)
+ {
+ while (!err && *pattern && **pattern)
+ err = add_arg (gpg, *(pattern++));
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
+ gpgme_data_t pubkey, gpgme_data_t seckey)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ if (!gpg)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* We need a special mechanism to get the fd of a pipe here, so that
+ we can use this for the %pubring and %secring parameters. We
+ don't have this yet, so we implement only the adding to the
+ standard keyrings. */
+ if (pubkey || seckey)
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ err = add_arg (gpg, "--gen-key");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err)
+ err = add_data (gpg, help_data, 0, 0);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_import (void *engine, gpgme_data_t keydata)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--import");
+ if (!err)
+ err = add_data (gpg, keydata, 0, 0);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_keylist (void *engine, const char *pattern, int secret_only,
+ gpgme_keylist_mode_t mode)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--with-colons");
+ if (!err)
+ err = add_arg (gpg, "--fixed-list-mode");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ if (!err)
+ err = add_arg (gpg, secret_only ? "--list-secret-keys"
+ : ((mode & GPGME_KEYLIST_MODE_SIGS)
+ ? "--check-sigs" : "--list-keys"));
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err && pattern && *pattern)
+ err = add_arg (gpg, pattern);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
+ int reserved, gpgme_keylist_mode_t mode)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ if (reserved)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = add_arg (gpg, "--with-colons");
+ if (!err)
+ err = add_arg (gpg, "--fixed-list-mode");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ if (!err)
+ err = add_arg (gpg, "--with-fingerprint");
+ if (!err)
+ err = add_arg (gpg, secret_only ? "--list-secret-keys"
+ : ((mode & GPGME_KEYLIST_MODE_SIGS)
+ ? "--check-sigs" : "--list-keys"));
+ if (!err)
+ err = add_arg (gpg, "--");
+
+ if (pattern)
+ {
+ while (!err && *pattern && **pattern)
+ err = add_arg (gpg, *(pattern++));
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
+ gpgme_sig_mode_t mode, int use_armor, int use_textmode,
+ int include_certs, gpgme_ctx_t ctx /* FIXME */)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ if (mode == GPGME_SIG_MODE_CLEAR)
+ err = add_arg (gpg, "--clearsign");
+ else
+ {
+ err = add_arg (gpg, "--sign");
+ if (!err && mode == GPGME_SIG_MODE_DETACH)
+ err = add_arg (gpg, "--detach");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err && use_textmode)
+ err = add_arg (gpg, "--textmode");
+ }
+
+ if (!err)
+ err = append_args_from_signers (gpg, ctx);
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_data (gpg, in, 0, 0);
+ if (!err)
+ err = add_data (gpg, out, 1, 1);
+
+ if (!err)
+ start (gpg);
+
+ return err;
+}
+
+static gpgme_error_t
+gpg_trustlist (void *engine, const char *pattern)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = add_arg (gpg, "--with-colons");
+ if (!err)
+ err = add_arg (gpg, "--list-trust-path");
+
+ /* Tell the gpg object about the data. */
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_arg (gpg, pattern);
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
+ gpgme_data_t plaintext)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err = 0;
+
+ if (plaintext)
+ {
+ /* Normal or cleartext signature. */
+
+ err = add_arg (gpg, "--output");
+ if (!err)
+ err = add_arg (gpg, "-");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, sig, 0, 0);
+ if (!err)
+ err = add_data (gpg, plaintext, 1, 1);
+ }
+ else
+ {
+ err = add_arg (gpg, "--verify");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, sig, -1, 0);
+ if (signed_text)
+ {
+ if (!err)
+ err = add_arg (gpg, "-");
+ if (!err)
+ err = add_data (gpg, signed_text, 0, 0);
+ }
+ }
+
+ if (!err)
+ err = start (gpg);
+
+ return err;
+}
+
+
+static void
+gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
+{
+ engine_gpg_t gpg = engine;
+
+ gpg->io_cbs = *io_cbs;
+}
+
+
+struct engine_ops _gpgme_engine_ops_gpg =
+ {
+ /* Static functions. */
+ _gpgme_get_gpg_path,
+ gpg_get_version,
+ gpg_get_req_version,
+ gpg_new,
+
+ /* Member functions. */
+ gpg_release,
+ gpg_set_status_handler,
+ gpg_set_command_handler,
+ gpg_set_colon_line_handler,
+ gpg_decrypt,
+ gpg_delete,
+ gpg_edit,
+ gpg_encrypt,
+ gpg_encrypt_sign,
+ gpg_export,
+ gpg_export_ext,
+ gpg_genkey,
+ gpg_import,
+ gpg_keylist,
+ gpg_keylist_ext,
+ gpg_sign,
+ gpg_trustlist,
+ gpg_verify,
+ gpg_set_io_cbs,
+ gpg_io_event,
+ gpg_cancel
+ };
diff --git a/branches/gpgme-1-0-branch/gpgme/sema.h b/branches/gpgme-1-0-branch/gpgme/sema.h
new file mode 100644
index 00000000..2c0842e1
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/sema.h
@@ -0,0 +1,66 @@
+/* sema.h - Definitions for semaphores.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 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 SEMA_H
+#define SEMA_H
+
+struct critsect_s
+{
+ const char *name;
+ void *private;
+};
+
+#define DEFINE_GLOBAL_LOCK(name) \
+ struct critsect_s name = { #name, NULL }
+#define DEFINE_STATIC_LOCK(name) \
+ static struct critsect_s name = { #name, NULL }
+
+#define DECLARE_LOCK(name) \
+ struct critsect_s name
+#define INIT_LOCK(a) \
+ do \
+ { \
+ (a).name = #a; \
+ (a).private = NULL; \
+ } \
+ while (0)
+#define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name))
+
+
+#define LOCK(name) \
+ do \
+ { \
+ _gpgme_sema_cs_enter (&(name)); \
+ } \
+ while (0)
+
+#define UNLOCK(name) \
+ do \
+ { \
+ _gpgme_sema_cs_leave (&(name)); \
+ } \
+ while (0)
+
+void _gpgme_sema_subsystem_init (void);
+void _gpgme_sema_cs_enter (struct critsect_s *s);
+void _gpgme_sema_cs_leave (struct critsect_s *s);
+void _gpgme_sema_cs_destroy (struct critsect_s *s);
+
+#endif /* SEMA_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/sign.c b/branches/gpgme-1-0-branch/gpgme/sign.c
new file mode 100644
index 00000000..2c0ae3f9
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/sign.c
@@ -0,0 +1,327 @@
+/* sign.c - Signing function.
+ 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 <string.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "context.h"
+#include "ops.h"
+#include "util.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_sign_result result;
+
+ /* A pointer to the next pointer of the last invalid signer in
+ the list. This makes appending new invalid signers painless
+ while preserving the order. */
+ gpgme_invalid_key_t *last_signer_p;
+
+ /* Likewise for signature information. */
+ gpgme_new_signature_t *last_sig_p;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+ gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers;
+ gpgme_new_signature_t sig = opd->result.signatures;
+
+ while (invalid_signer)
+ {
+ gpgme_invalid_key_t next = invalid_signer->next;
+ if (invalid_signer->fpr)
+ free (invalid_signer->fpr);
+ free (invalid_signer);
+ invalid_signer = next;
+ }
+
+ while (sig)
+ {
+ gpgme_new_signature_t next = sig->next;
+ free (sig->fpr);
+ free (sig);
+ sig = next;
+ }
+}
+
+
+gpgme_sign_result_t
+gpgme_op_sign_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+static gpgme_error_t
+parse_sig_created (char *args, gpgme_new_signature_t *sigp)
+{
+ gpgme_new_signature_t sig;
+ char *tail;
+
+ sig = malloc (sizeof (*sig));
+ if (!sig)
+ return gpg_error_from_errno (errno);
+
+ sig->next = NULL;
+ switch (*args)
+ {
+ case 'S':
+ sig->type = GPGME_SIG_MODE_NORMAL;
+ break;
+
+ case 'D':
+ sig->type = GPGME_SIG_MODE_DETACH;
+ break;
+
+ case 'C':
+ sig->type = GPGME_SIG_MODE_CLEAR;
+ break;
+
+ default:
+ /* The backend engine is not behaving. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+
+ args++;
+ if (*args != ' ')
+ {
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+
+ errno = 0;
+ sig->pubkey_algo = strtol (args, &tail, 0);
+ if (errno || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ args = tail;
+
+ sig->hash_algo = strtol (args, &tail, 0);
+ if (errno || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ args = tail;
+
+ sig->sig_class = strtol (args, &tail, 0);
+ sig->class = sig->sig_class;
+ sig->_obsolete_class = sig->sig_class;
+ if (errno || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ args = tail;
+
+ sig->timestamp = _gpgme_parse_timestamp (args, &tail);
+ if (sig->timestamp == -1 || args == tail || *tail != ' ')
+ {
+ /* The crypto backend does not behave. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ args = tail;
+ while (*args == ' ')
+ args++;
+
+ if (!*args)
+ {
+ /* The crypto backend does not behave. */
+ free (sig);
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+
+ tail = strchr (args, ' ');
+ if (tail)
+ *tail = '\0';
+
+ sig->fpr = strdup (args);
+ if (!sig->fpr)
+ {
+ int saved_errno = errno;
+ free (sig);
+ return gpg_error_from_errno (saved_errno);
+ }
+ *sigp = sig;
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_passphrase_status_handler (priv, code, args);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ switch (code)
+ {
+ case GPGME_STATUS_SIG_CREATED:
+ err = parse_sig_created (args, opd->last_sig_p);
+ if (err)
+ return err;
+
+ opd->last_sig_p = &(*opd->last_sig_p)->next;
+ break;
+
+ case GPGME_STATUS_INV_RECP:
+ err = _gpgme_parse_inv_recp (args, opd->last_signer_p);
+ if (err)
+ return err;
+
+ opd->last_signer_p = &(*opd->last_signer_p)->next;
+ break;
+
+ case GPGME_STATUS_EOF:
+ if (opd->result.invalid_signers)
+ return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+ break;
+
+ default:
+ break;
+ }
+ return err;
+}
+
+
+static gpgme_error_t
+sign_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_sign_status_handler (priv, code, args);
+ return err;
+}
+
+
+gpgme_error_t
+_gpgme_op_sign_init_result (gpgme_ctx_t ctx)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook,
+ sizeof (*opd), release_op_data);
+ opd = hook;
+ if (err)
+ return err;
+ opd->last_signer_p = &opd->result.invalid_signers;
+ opd->last_sig_p = &opd->result.signatures;
+ return 0;
+}
+
+
+static gpgme_error_t
+sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain,
+ gpgme_data_t sig, gpgme_sig_mode_t mode)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_sign_init_result (ctx);
+ if (err)
+ return err;
+
+ if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
+ && mode != GPGME_SIG_MODE_CLEAR)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!plain)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!sig)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (ctx->passphrase_cb)
+ {
+ err = _gpgme_engine_set_command_handler
+ (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL);
+ if (err)
+ return err;
+ }
+
+ _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler,
+ ctx);
+
+ return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor,
+ ctx->use_textmode, ctx->include_certs,
+ ctx /* FIXME */);
+}
+
+
+/* Sign the plaintext PLAIN and store the signature in SIG. */
+gpgme_error_t
+gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
+ gpgme_sig_mode_t mode)
+{
+ return sign_start (ctx, 0, plain, sig, mode);
+}
+
+
+/* Sign the plaintext PLAIN and store the signature in SIG. */
+gpgme_error_t
+gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig,
+ gpgme_sig_mode_t mode)
+{
+ gpgme_error_t err = sign_start (ctx, 1, plain, sig, mode);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/signers.c b/branches/gpgme-1-0-branch/gpgme/signers.c
new file mode 100644
index 00000000..a5662a27
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/signers.c
@@ -0,0 +1,94 @@
+/* signers.c - Maintain signer sets.
+ Copyright (C) 2001 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "util.h"
+#include "context.h"
+
+
+/* Delete all signers from CTX. */
+void
+gpgme_signers_clear (gpgme_ctx_t ctx)
+{
+ unsigned int i;
+
+ if (!ctx || !ctx->signers)
+ return;
+
+ for (i = 0; i < ctx->signers_len; i++)
+ {
+ assert (ctx->signers[i]);
+ gpgme_key_unref (ctx->signers[i]);
+ ctx->signers[i] = NULL;
+ }
+ ctx->signers_len = 0;
+}
+
+/* Add KEY to list of signers in CTX. */
+gpgme_error_t
+gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key)
+{
+ if (!ctx || !key)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (ctx->signers_len == ctx->signers_size)
+ {
+ gpgme_key_t *newarr;
+ int n = ctx->signers_size + 5;
+ int j;
+
+ newarr = realloc (ctx->signers, n * sizeof (*newarr));
+ if (!newarr)
+ return gpg_error_from_errno (errno);
+ for (j = ctx->signers_size; j < n; j++)
+ newarr[j] = NULL;
+ ctx->signers = newarr;
+ ctx->signers_size = n;
+ }
+
+ gpgme_key_ref (key);
+ ctx->signers[ctx->signers_len++] = key;
+ return 0;
+}
+
+
+/* Return the SEQth signer's key in CTX with one reference. */
+gpgme_key_t
+gpgme_signers_enum (const gpgme_ctx_t ctx, int seq)
+{
+ unsigned int seqno;
+
+ if (!ctx || seq < 0)
+ return NULL;
+
+ seqno = (unsigned int) seq;
+ if (seqno >= ctx->signers_len)
+ return NULL;
+ gpgme_key_ref (ctx->signers[seqno]);
+ return ctx->signers[seqno];
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/stpcpy.c b/branches/gpgme-1-0-branch/gpgme/stpcpy.c
new file mode 100644
index 00000000..a01636cd
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/stpcpy.c
@@ -0,0 +1,50 @@
+/* stpcpy.c -- copy a string and return pointer to end of new string
+ Copyright (C) 1992, 1995, 1997, 1998 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to [email protected].
+
+ This program 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, or (at your option) any
+ later version.
+
+ This program 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. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#undef __stpcpy
+#undef stpcpy
+
+#ifndef weak_alias
+# define __stpcpy stpcpy
+#endif
+
+/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
+char *
+__stpcpy (char *dest, const char *src)
+{
+ register char *d = dest;
+ register const char *s = src;
+
+ do
+ *d++ = *s;
+ while (*s++ != '\0');
+
+ return d - 1;
+}
+#ifdef weak_alias
+weak_alias (__stpcpy, stpcpy)
+#endif
diff --git a/branches/gpgme-1-0-branch/gpgme/trust-item.c b/branches/gpgme-1-0-branch/gpgme/trust-item.c
new file mode 100644
index 00000000..bc60df42
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/trust-item.c
@@ -0,0 +1,170 @@
+/* trust-item.c - Trust item objects.
+ 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 <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "util.h"
+#include "ops.h"
+#include "sema.h"
+
+
+/* Protects all reference counters in trust items. All other accesses
+ to a trust item are either read only or happen before the trust
+ item is available to the user. */
+DEFINE_STATIC_LOCK (trust_item_ref_lock);
+
+
+/* Create a new trust item. */
+gpgme_error_t
+_gpgme_trust_item_new (gpgme_trust_item_t *r_item)
+{
+ gpgme_trust_item_t item;
+
+ item = calloc (1, sizeof *item);
+ if (!item)
+ return gpg_error_from_errno (errno);
+ item->_refs = 1;
+ item->keyid = item->_keyid;
+ item->_keyid[16] = '\0';
+ item->owner_trust = item->_owner_trust;
+ item->_owner_trust[1] = '\0';
+ item->validity = item->_validity;
+ item->_validity[1] = '\0';
+ *r_item = item;
+ return 0;
+}
+
+
+/* Acquire a reference to ITEM. */
+void
+gpgme_trust_item_ref (gpgme_trust_item_t item)
+{
+ LOCK (trust_item_ref_lock);
+ item->_refs++;
+ UNLOCK (trust_item_ref_lock);
+}
+
+
+/* gpgme_trust_item_unref releases the trust item object. Note that
+ this function may not do an actual release if there are other
+ shallow copies of the object. You have to call this function for
+ every newly created trust item object as well as for every
+ gpgme_trust_item_ref() done on the trust item object. */
+void
+gpgme_trust_item_unref (gpgme_trust_item_t item)
+{
+ LOCK (trust_item_ref_lock);
+ assert (item->_refs > 0);
+ if (--item->_refs)
+ {
+ UNLOCK (trust_item_ref_lock);
+ return;
+ }
+ UNLOCK (trust_item_ref_lock);
+
+ if (item->name)
+ free (item->name);
+ free (item);
+}
+
+
+/* Compatibility interfaces. */
+void
+gpgme_trust_item_release (gpgme_trust_item_t item)
+{
+ gpgme_trust_item_unref (item);
+}
+
+/* Return the value of the attribute WHAT of ITEM, which has to be
+ representable by a string. */
+const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item,
+ _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ const char *val = NULL;
+
+ if (!item)
+ return NULL;
+ if (reserved)
+ return NULL;
+ if (idx)
+ return NULL;
+
+ switch (what)
+ {
+ case GPGME_ATTR_KEYID:
+ val = item->keyid;
+ break;
+
+ case GPGME_ATTR_OTRUST:
+ val = item->owner_trust;
+ break;
+
+ case GPGME_ATTR_VALIDITY:
+ val = item->validity;
+ break;
+
+ case GPGME_ATTR_USERID:
+ val = item->name;
+ break;
+
+ default:
+ break;
+ }
+ return val;
+}
+
+
+/* Return the value of the attribute WHAT of KEY, which has to be
+ representable by an integer. IDX specifies a running index if the
+ attribute appears more than once in the key. */
+int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what,
+ const void *reserved, int idx)
+{
+ int val = 0;
+
+ if (!item)
+ return 0;
+ if (reserved)
+ return 0;
+ if (idx)
+ return 0;
+
+ switch (what)
+ {
+ case GPGME_ATTR_LEVEL:
+ val = item->level;
+ break;
+
+ case GPGME_ATTR_TYPE:
+ val = item->type;
+ break;
+
+ default:
+ break;
+ }
+ return val;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/trustlist.c b/branches/gpgme-1-0-branch/gpgme/trustlist.c
new file mode 100644
index 00000000..942cc53b
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/trustlist.c
@@ -0,0 +1,245 @@
+/* trustlist.c - Trust item listing.
+ 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 <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+
+struct trust_queue_item_s
+{
+ struct trust_queue_item_s *next;
+ gpgme_trust_item_t item;
+};
+
+typedef struct
+{
+ /* Something new is available. */
+ int trust_cond;
+ struct trust_queue_item_s *trust_queue;
+} *op_data_t;
+
+
+
+static gpgme_error_t
+trustlist_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ return 0;
+}
+
+
+/* This handler is used to parse the output of --list-trust-path:
+ Format:
+ level:keyid:type:recno:ot:val:mc:cc:name:
+ With TYPE = U for a user ID
+ K for a key
+ The RECNO is either the one of the dir record or the one of the uid
+ record. OT is the the usual trust letter and only availabel on K
+ lines. VAL is the calcualted validity MC is the marginal trust
+ 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 gpgme_error_t
+trustlist_colon_handler (void *priv, char *line)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ char *p, *pend;
+ int field = 0;
+ gpgme_trust_item_t item = NULL;
+
+ if (!line)
+ return 0; /* EOF */
+
+ for (p = line; p; p = pend)
+ {
+ field++;
+ pend = strchr (p, ':');
+ if (pend)
+ *pend++ = 0;
+
+ switch (field)
+ {
+ case 1: /* level */
+ err = _gpgme_trust_item_new (&item);
+ if (err)
+ return err;
+ item->level = atoi (p);
+ break;
+ case 2: /* long keyid */
+ if (strlen (p) == DIM(item->keyid) - 1)
+ strcpy (item->keyid, p);
+ break;
+ case 3: /* type */
+ item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
+ break;
+ case 5: /* owner trust */
+ item->_owner_trust[0] = *p;
+ break;
+ case 6: /* validity */
+ item->_validity[0] = *p;
+ break;
+ case 9: /* user ID */
+ item->name = strdup (p);
+ if (!item->name)
+ {
+ int saved_errno = errno;
+ gpgme_trust_item_unref (item);
+ return gpg_error_from_errno (saved_errno);
+ }
+ break;
+ }
+ }
+
+ if (item)
+ _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item);
+ return 0;
+}
+
+
+void
+_gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) data;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ gpgme_trust_item_t item = (gpgme_trust_item_t) type_data;
+ struct trust_queue_item_s *q, *q2;
+
+ assert (type == GPGME_EVENT_NEXT_TRUSTITEM);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return;
+
+ q = malloc (sizeof *q);
+ if (!q)
+ {
+ gpgme_trust_item_unref (item);
+ /* FIXME: GPGME_Out_Of_Core; */
+ return;
+ }
+ q->item = item;
+ q->next = NULL;
+ /* FIXME: Use a tail pointer */
+ q2 = opd->trust_queue;
+ if (!q2)
+ opd->trust_queue = q;
+ else
+ {
+ while (q2->next)
+ q2 = q2->next;
+ q2->next = q;
+ }
+ /* FIXME: unlock queue */
+ opd->trust_cond = 1;
+}
+
+
+gpgme_error_t
+gpgme_op_trustlist_start (gpgme_ctx_t ctx, const char *pattern, int max_level)
+{
+ gpgme_error_t err = 0;
+ void *hook;
+ op_data_t opd;
+
+ if (!pattern || !*pattern)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_reset (ctx, 2);
+ if (err)
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook,
+ sizeof (*opd), NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine,
+ trustlist_status_handler, ctx);
+ err = _gpgme_engine_set_colon_line_handler (ctx->engine,
+ trustlist_colon_handler, ctx);
+ if (err)
+ return err;
+
+ return _gpgme_engine_op_trustlist (ctx->engine, pattern);
+}
+
+
+gpgme_error_t
+gpgme_op_trustlist_next (gpgme_ctx_t ctx, gpgme_trust_item_t *r_item)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ struct trust_queue_item_s *q;
+
+ if (!r_item)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ *r_item = NULL;
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ if (!opd->trust_queue)
+ {
+ err = _gpgme_wait_on_condition (ctx, &opd->trust_cond);
+ if (err)
+ return err;
+ if (!opd->trust_cond)
+ return gpg_error (GPG_ERR_EOF);
+ opd->trust_cond = 0;
+ assert (opd->trust_queue);
+ }
+ q = opd->trust_queue;
+ opd->trust_queue = q->next;
+
+ *r_item = q->item;
+ free (q);
+ return 0;
+}
+
+
+/* Terminate a pending trustlist operation within CTX. */
+gpgme_error_t
+gpgme_op_trustlist_end (gpgme_ctx_t ctx)
+{
+ if (!ctx)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ return 0;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/util.h b/branches/gpgme-1-0-branch/gpgme/util.h
new file mode 100644
index 00000000..085b37c1
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/util.h
@@ -0,0 +1,90 @@
+/* util.h
+ 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 UTIL_H
+#define UTIL_H
+
+#include "gpgme.h"
+
+
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+
+
+/*-- {posix,w32}-util.c --*/
+const char *_gpgme_get_gpg_path (void);
+const char *_gpgme_get_gpgsm_path (void);
+
+
+/*-- replacement functions in <funcname>.c --*/
+#ifdef HAVE_CONFIG_H
+#ifndef HAVE_STPCPY
+char *stpcpy (char *a, const char *b);
+#endif
+
+#if !HAVE_VASPRINTF
+#include <stdarg.h>
+int vasprintf (char **result, const char *format, va_list args);
+int asprintf (char **result, const char *format, ...);
+#endif
+#endif
+
+
+/*-- conversion.c --*/
+/* Convert two hexadecimal digits from STR to the value they
+ represent. Returns -1 if one of the characters is not a
+ hexadecimal digit. */
+int _gpgme_hextobyte (const char *str);
+
+/* Decode the C formatted string SRC and store the result in the
+ buffer *DESTP which is LEN bytes long. If LEN is zero, then a
+ large enough buffer is allocated with malloc and *DESTP is set to
+ the result. Currently, LEN is only used to specify if allocation
+ is desired or not, the caller is expected to make sure that *DESTP
+ is large enough if LEN is not zero. */
+gpgme_error_t _gpgme_decode_c_string (const char *src, char **destp,
+ size_t len);
+
+/* Decode the percent escaped string SRC and store the result in the
+ buffer *DESTP which is LEN bytes long. If LEN is zero, then a
+ large enough buffer is allocated with malloc and *DESTP is set to
+ the result. Currently, LEN is only used to specify if allocation
+ is desired or not, the caller is expected to make sure that *DESTP
+ is large enough if LEN is not zero. */
+gpgme_error_t _gpgme_decode_percent_string (const char *src, char **destp,
+ size_t len);
+
+
+/* Parse the string TIMESTAMP into a time_t. The string may either be
+ seconds since Epoch or in the ISO 8601 format like
+ "20390815T143012". Returns 0 for an empty string or seconds since
+ Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
+ point to the next non-parsed character in TIMESTRING. */
+time_t _gpgme_parse_timestamp (const char *timestamp, char **endp);
+
+
+gpgme_error_t _gpgme_map_gnupg_error (char *err);
+
+
+/* Retrieve the environment variable NAME and return a copy of it in a
+ malloc()'ed buffer in *VALUE. If the environment variable is not
+ set, return NULL in *VALUE. */
+gpgme_error_t _gpgme_getenv (const char *name, char **value);
+
+#endif /* UTIL_H */
diff --git a/branches/gpgme-1-0-branch/gpgme/vasprintf.c b/branches/gpgme-1-0-branch/gpgme/vasprintf.c
new file mode 100644
index 00000000..77113a31
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/vasprintf.c
@@ -0,0 +1,192 @@
+/* Like vsprintf but provides a pointer to malloc'd storage, which must
+ be freed by the caller.
+ Copyright (C) 1994, 2002 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. 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>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+#ifndef va_copy /* According to POSIX, va_copy is a macro. */
+#if defined (__GNUC__) && defined (__PPC__) \
+ && (defined (_CALL_SYSV) || defined (_WIN32))
+#define va_copy(d, s) (*(d) = *(s))
+#elif defined (MUST_COPY_VA_BYVAL)
+#define va_copy(d, s) ((d) = (s))
+#else
+#define va_copy(d, s) memcpy ((d), (s), sizeof (va_list))
+#endif
+#endif
+
+
+#ifdef TEST
+int global_total_width;
+#endif
+
+static int int_vasprintf (char **, const char *, va_list *);
+
+static int
+int_vasprintf (result, format, args)
+ char **result;
+ const char *format;
+ va_list *args;
+{
+ const char *p = format;
+ /* Add one to make sure that it is never zero, which might cause malloc
+ to return NULL. */
+ int total_width = strlen (format) + 1;
+ va_list ap;
+
+ va_copy (ap, *args);
+
+ while (*p != '\0')
+ {
+ if (*p++ == '%')
+ {
+ while (strchr ("-+ #0", *p))
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, (char **) &p, 10);
+ if (*p == '.')
+ {
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, (char **) &p, 10);
+ }
+ while (strchr ("hlL", *p))
+ ++p;
+ /* Should be big enough for any format specifier except %s and floats. */
+ total_width += 30;
+ switch (*p)
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'c':
+ (void) va_arg (ap, int);
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ (void) va_arg (ap, double);
+ /* Since an ieee double can have an exponent of 307, we'll
+ make the buffer wide enough to cover the gross case. */
+ total_width += 307;
+ break;
+ case 's':
+ {
+ char *tmp = va_arg (ap, char *);
+ if (tmp)
+ total_width += strlen (tmp);
+ else /* in case the vsprintf does prints a text */
+ total_width += 25; /* e.g. "(null pointer reference)" */
+ }
+ break;
+ case 'p':
+ case 'n':
+ (void) va_arg (ap, char *);
+ break;
+ }
+ p++;
+ }
+ }
+#ifdef TEST
+ global_total_width = total_width;
+#endif
+ *result = malloc (total_width);
+ if (*result != NULL)
+ return vsprintf (*result, format, *args);
+ else
+ return 0;
+}
+
+int
+vasprintf (result, format, args)
+ char **result;
+ const char *format;
+#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
+ _BSD_VA_LIST_ args;
+#else
+ va_list args;
+#endif
+{
+ return int_vasprintf (result, format, &args);
+}
+
+
+int
+asprintf (char **buf, const char *fmt, ...)
+{
+ int status;
+ va_list ap;
+
+ va_start (ap, fmt);
+ status = vasprintf (buf, fmt, ap);
+ va_end (ap);
+ return status;
+}
+
+
+#ifdef TEST
+void
+checkit (const char* format, ...)
+{
+ va_list args;
+ char *result;
+
+ va_start (args, format);
+ vasprintf (&result, format, args);
+ if (strlen (result) < global_total_width)
+ printf ("PASS: ");
+ else
+ printf ("FAIL: ");
+ printf ("%d %s\n", global_total_width, result);
+}
+
+int
+main (void)
+{
+ checkit ("%d", 0x12345678);
+ checkit ("%200d", 5);
+ checkit ("%.300d", 6);
+ checkit ("%100.150d", 7);
+ checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
+777777777777777777333333333333366666666666622222222222777777777777733333");
+ checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
+}
+#endif /* TEST */
diff --git a/branches/gpgme-1-0-branch/gpgme/verify.c b/branches/gpgme-1-0-branch/gpgme/verify.c
new file mode 100644
index 00000000..80593e9d
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/verify.c
@@ -0,0 +1,879 @@
+/* verify.c - Signature verification.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2002, 2003, 2004 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+ struct _gpgme_op_verify_result result;
+
+ gpgme_signature_t current_sig;
+ int did_prepare_new_sig;
+ int only_newsig_seen;
+} *op_data_t;
+
+
+static void
+release_op_data (void *hook)
+{
+ op_data_t opd = (op_data_t) hook;
+ gpgme_signature_t sig = opd->result.signatures;
+
+ while (sig)
+ {
+ gpgme_signature_t next = sig->next;
+ gpgme_sig_notation_t notation = sig->notations;
+
+ while (notation)
+ {
+ gpgme_sig_notation_t next_nota = notation->next;
+
+ if (notation->name)
+ free (notation->name);
+ if (notation->value)
+ free (notation->value);
+ notation = next_nota;
+ }
+
+ if (sig->fpr)
+ free (sig->fpr);
+ free (sig);
+ sig = next;
+ }
+}
+
+
+gpgme_verify_result_t
+gpgme_op_verify_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+ gpgme_error_t err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
+ opd = hook;
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+
+/* Build a summary vector from RESULT. */
+static void
+calc_sig_summary (gpgme_signature_t sig)
+{
+ unsigned long sum = 0;
+
+ if (sig->validity == GPGME_VALIDITY_FULL
+ || sig->validity == GPGME_VALIDITY_ULTIMATE)
+ {
+ if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
+ || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
+ || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
+ sum |= GPGME_SIGSUM_GREEN;
+ }
+ else if (sig->validity == GPGME_VALIDITY_NEVER)
+ {
+ if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR
+ || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED
+ || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED)
+ sum |= GPGME_SIGSUM_RED;
+ }
+ else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE)
+ sum |= GPGME_SIGSUM_RED;
+
+ if (sig->validity == GPGME_VALIDITY_UNKNOWN)
+ {
+ if (gpg_err_code (sig->validity_reason) == GPG_ERR_CRL_TOO_OLD)
+ sum |= GPGME_SIGSUM_CRL_TOO_OLD;
+ }
+
+ /* FIXME: handle the case when key and message are expired. */
+ switch (gpg_err_code (sig->status))
+ {
+ case GPG_ERR_SIG_EXPIRED:
+ sum |= GPGME_SIGSUM_SIG_EXPIRED;
+ break;
+
+ case GPG_ERR_KEY_EXPIRED:
+ sum |= GPGME_SIGSUM_KEY_EXPIRED;
+ break;
+
+ case GPG_ERR_NO_PUBKEY:
+ sum |= GPGME_SIGSUM_KEY_MISSING;
+ break;
+
+ case GPG_ERR_BAD_SIGNATURE:
+ case GPG_ERR_NO_ERROR:
+ break;
+
+ default:
+ sum |= GPGME_SIGSUM_SYS_ERROR;
+ break;
+ }
+
+ if (sig->wrong_key_usage)
+ sum |= GPGME_SIGSUM_BAD_POLICY;
+
+ /* Set the valid flag when the signature is unquestionable
+ valid. */
+ if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN))
+ sum |= GPGME_SIGSUM_VALID;
+
+ sig->summary = sum;
+}
+
+
+static gpgme_error_t
+prepare_new_sig (op_data_t opd)
+{
+ gpgme_signature_t sig;
+
+ if (opd->only_newsig_seen && opd->current_sig)
+ {
+ /* We have only seen the NEWSIG status and nothing else - we
+ better skip this signature therefore and reuse it for the
+ next possible signature. */
+ sig = opd->current_sig;
+ memset (sig, 0, sizeof *sig);
+ assert (opd->result.signatures == sig);
+ }
+ else
+ {
+ sig = calloc (1, sizeof (*sig));
+ if (!sig)
+ return gpg_error_from_errno (errno);
+ if (!opd->result.signatures)
+ opd->result.signatures = sig;
+ if (opd->current_sig)
+ opd->current_sig->next = sig;
+ opd->current_sig = sig;
+ }
+ opd->did_prepare_new_sig = 1;
+ opd->only_newsig_seen = 0;
+ return 0;
+}
+
+static gpgme_error_t
+parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args)
+{
+ gpgme_signature_t sig;
+ char *end = strchr (args, ' ');
+
+ if (end)
+ {
+ *end = '\0';
+ end++;
+ }
+
+ if (!opd->did_prepare_new_sig)
+ {
+ gpg_error_t err;
+
+ err = prepare_new_sig (opd);
+ if (err)
+ return err;
+ }
+ assert (opd->did_prepare_new_sig);
+ opd->did_prepare_new_sig = 0;
+
+ assert (opd->current_sig);
+ sig = opd->current_sig;
+
+ /* FIXME: We should set the source of the state. */
+ switch (code)
+ {
+ case GPGME_STATUS_GOODSIG:
+ sig->status = gpg_error (GPG_ERR_NO_ERROR);
+ break;
+
+ case GPGME_STATUS_EXPSIG:
+ sig->status = gpg_error (GPG_ERR_SIG_EXPIRED);
+ break;
+
+ case GPGME_STATUS_EXPKEYSIG:
+ sig->status = gpg_error (GPG_ERR_KEY_EXPIRED);
+ break;
+
+ case GPGME_STATUS_BADSIG:
+ sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE);
+ break;
+
+ case GPGME_STATUS_REVKEYSIG:
+ sig->status = gpg_error (GPG_ERR_CERT_REVOKED);
+ break;
+
+ case GPGME_STATUS_ERRSIG:
+ if (end)
+ {
+ int i = 0;
+ /* The return code is the 6th argument, if it is 9, the
+ problem is a missing key. */
+ while (end && i < 4)
+ {
+ end = strchr (end, ' ');
+ if (end)
+ end++;
+ i++;
+ }
+ if (end && end[0] && (!end[1] || end[1] == ' '))
+ {
+ switch (end[0])
+ {
+ case '4':
+ sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+ break;
+
+ case '9':
+ sig->status = gpg_error (GPG_ERR_NO_PUBKEY);
+ break;
+
+ default:
+ sig->status = gpg_error (GPG_ERR_GENERAL);
+ }
+ }
+ }
+ else
+ sig->status = gpg_error (GPG_ERR_GENERAL);
+ break;
+
+ default:
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+ if (*args)
+ {
+ sig->fpr = strdup (args);
+ if (!sig->fpr)
+ return gpg_error_from_errno (errno);
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+parse_valid_sig (gpgme_signature_t sig, char *args)
+{
+ char *end = strchr (args, ' ');
+
+ if (end)
+ {
+ *end = '\0';
+ end++;
+ }
+
+ if (!*args)
+ /* We require at least the fingerprint. */
+ return gpg_error (GPG_ERR_GENERAL);
+
+ if (sig->fpr)
+ free (sig->fpr);
+ sig->fpr = strdup (args);
+ if (!sig->fpr)
+ return gpg_error_from_errno (errno);
+
+ end = strchr (end, ' ');
+ if (end)
+ {
+ char *tail;
+
+ sig->timestamp = _gpgme_parse_timestamp (end, &tail);
+ if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' '))
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ end = tail;
+
+ sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail);
+ if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' '))
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+ gpgme_sig_notation_t *lastp = &sig->notations;
+ gpgme_sig_notation_t notation = sig->notations;
+ char *end = strchr (args, ' ');
+
+ if (end)
+ *end = '\0';
+
+ if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL)
+ {
+ /* FIXME: We could keep a pointer to the last notation in the list. */
+ while (notation && notation->value)
+ {
+ lastp = &notation->next;
+ notation = notation->next;
+ }
+
+ if (notation)
+ /* There is another notation name without data for the
+ previous one. The crypto backend misbehaves. */
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ notation = malloc (sizeof (*sig));
+ if (!notation)
+ return gpg_error_from_errno (errno);
+ notation->next = NULL;
+
+ if (code == GPGME_STATUS_NOTATION_NAME)
+ {
+ int len = strlen (args) + 1;
+
+ notation->name = malloc (len);
+ if (!notation->name)
+ {
+ int saved_errno = errno;
+ free (notation);
+ return gpg_error_from_errno (saved_errno);
+ }
+ err = _gpgme_decode_percent_string (args, &notation->name, len);
+ if (err)
+ {
+ free (notation->name);
+ free (notation);
+ return err;
+ }
+
+ notation->value = NULL;
+ }
+ else
+ {
+ int len = strlen (args) + 1;
+
+ notation->name = NULL;
+ notation->value = malloc (len);
+ if (!notation->value)
+ {
+ int saved_errno = errno;
+ free (notation);
+ return gpg_error_from_errno (saved_errno);
+ }
+ err = _gpgme_decode_percent_string (args, &notation->value, len);
+ if (err)
+ {
+ free (notation->value);
+ free (notation);
+ return err;
+ }
+ }
+ *lastp = notation;
+ }
+ else if (code == GPGME_STATUS_NOTATION_DATA)
+ {
+ int len = strlen (args) + 1;
+ char *dest;
+
+ /* FIXME: We could keep a pointer to the last notation in the list. */
+ while (notation && notation->next)
+ {
+ lastp = &notation->next;
+ notation = notation->next;
+ }
+
+ if (!notation || !notation->name)
+ /* There is notation data without a previous notation
+ name. The crypto backend misbehaves. */
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ if (!notation->value)
+ {
+ dest = notation->value = malloc (len);
+ if (!dest)
+ return gpg_error_from_errno (errno);
+ }
+ else
+ {
+ int cur_len = strlen (notation->value);
+ dest = realloc (notation->value, len + strlen (notation->value));
+ if (!dest)
+ return gpg_error_from_errno (errno);
+ notation->value = dest;
+ dest += cur_len;
+ }
+
+ err = _gpgme_decode_percent_string (args, &dest, len);
+ if (err)
+ return err;
+ }
+ else
+ return gpg_error (GPG_ERR_INV_ENGINE);
+ return 0;
+}
+
+
+static gpgme_error_t
+parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args)
+{
+ char *end = strchr (args, ' ');
+
+ if (end)
+ *end = '\0';
+
+ switch (code)
+ {
+ case GPGME_STATUS_TRUST_UNDEFINED:
+ default:
+ sig->validity = GPGME_VALIDITY_UNKNOWN;
+ break;
+
+ case GPGME_STATUS_TRUST_NEVER:
+ sig->validity = GPGME_VALIDITY_NEVER;
+ break;
+
+ case GPGME_STATUS_TRUST_MARGINAL:
+ sig->validity = GPGME_VALIDITY_MARGINAL;
+ break;
+
+ case GPGME_STATUS_TRUST_FULLY:
+ case GPGME_STATUS_TRUST_ULTIMATE:
+ sig->validity = GPGME_VALIDITY_FULL;
+ break;
+ }
+
+ if (*args)
+ sig->validity_reason = _gpgme_map_gnupg_error (args);
+ else
+ sig->validity_reason = 0;
+
+ return 0;
+}
+
+
+static gpgme_error_t
+parse_error (gpgme_signature_t sig, char *args)
+{
+ gpgme_error_t err;
+ char *where = strchr (args, ' ');
+ char *which;
+
+ if (where)
+ {
+ *where = '\0';
+ which = where + 1;
+
+ where = strchr (which, ' ');
+ if (where)
+ *where = '\0';
+
+ where = args;
+ }
+ else
+ return gpg_error (GPG_ERR_INV_ENGINE);
+
+ err = _gpgme_map_gnupg_error (which);
+
+ if (!strcmp (where, "verify.findkey"))
+ sig->status = err;
+ else if (!strcmp (where, "verify.keyusage")
+ && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
+ sig->wrong_key_usage = 1;
+
+ return 0;
+}
+
+
+gpgme_error_t
+_gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ gpgme_signature_t sig;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL);
+ opd = hook;
+ if (err)
+ return err;
+
+ sig = opd->current_sig;
+
+ switch (code)
+ {
+ case GPGME_STATUS_NEWSIG:
+ if (sig)
+ calc_sig_summary (sig);
+ err = prepare_new_sig (opd);
+ opd->only_newsig_seen = 1;
+ return err;
+
+ case GPGME_STATUS_GOODSIG:
+ case GPGME_STATUS_EXPSIG:
+ case GPGME_STATUS_EXPKEYSIG:
+ case GPGME_STATUS_BADSIG:
+ case GPGME_STATUS_ERRSIG:
+ case GPGME_STATUS_REVKEYSIG:
+ if (sig && !opd->did_prepare_new_sig)
+ calc_sig_summary (sig);
+ opd->only_newsig_seen = 0;
+ return parse_new_sig (opd, code, args);
+
+ case GPGME_STATUS_VALIDSIG:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_valid_sig (sig, args)
+ : gpg_error (GPG_ERR_INV_ENGINE);
+
+ case GPGME_STATUS_NODATA:
+ opd->only_newsig_seen = 0;
+ if (!sig)
+ return gpg_error (GPG_ERR_NO_DATA);
+ sig->status = gpg_error (GPG_ERR_NO_DATA);
+ break;
+
+ case GPGME_STATUS_UNEXPECTED:
+ opd->only_newsig_seen = 0;
+ if (!sig)
+ return gpg_error (GPG_ERR_GENERAL);
+ sig->status = gpg_error (GPG_ERR_NO_DATA);
+ break;
+
+ case GPGME_STATUS_NOTATION_NAME:
+ case GPGME_STATUS_NOTATION_DATA:
+ case GPGME_STATUS_POLICY_URL:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_notation (sig, code, args)
+ : gpg_error (GPG_ERR_INV_ENGINE);
+
+ case GPGME_STATUS_TRUST_UNDEFINED:
+ case GPGME_STATUS_TRUST_NEVER:
+ case GPGME_STATUS_TRUST_MARGINAL:
+ case GPGME_STATUS_TRUST_FULLY:
+ case GPGME_STATUS_TRUST_ULTIMATE:
+ opd->only_newsig_seen = 0;
+ return sig ? parse_trust (sig, code, args)
+ : gpg_error (GPG_ERR_INV_ENGINE);
+
+ case GPGME_STATUS_ERROR:
+ opd->only_newsig_seen = 0;
+ /* The error status is informational, so we don't return an
+ error code if we are not ready to process this status. */
+ return sig ? parse_error (sig, args) : 0;
+
+ case GPGME_STATUS_EOF:
+ if (sig && !opd->did_prepare_new_sig)
+ calc_sig_summary (sig);
+ if (opd->only_newsig_seen && sig)
+ {
+ gpgme_signature_t sig2;
+ /* The last signature has no valid information - remove it
+ from the list. */
+ assert (!sig->next);
+ if (sig == opd->result.signatures)
+ opd->result.signatures = NULL;
+ else
+ {
+ for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next)
+ if (sig2->next == sig)
+ {
+ sig2->next = NULL;
+ break;
+ }
+ }
+ /* Note that there is no need to release the members of SIG
+ because we won't be here if they have been set. */
+ free (sig);
+ opd->current_sig = NULL;
+ }
+ opd->only_newsig_seen = 0;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static gpgme_error_t
+verify_status_handler (void *priv, gpgme_status_code_t code, char *args)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_progress_status_handler (priv, code, args);
+ if (!err)
+ err = _gpgme_verify_status_handler (priv, code, args);
+ return err;
+}
+
+
+gpgme_error_t
+_gpgme_op_verify_init_result (gpgme_ctx_t ctx)
+{
+ void *hook;
+ op_data_t opd;
+
+ return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook,
+ sizeof (*opd), release_op_data);
+}
+
+
+static gpgme_error_t
+verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig,
+ gpgme_data_t signed_text, gpgme_data_t plaintext)
+{
+ gpgme_error_t err;
+
+ err = _gpgme_op_reset (ctx, synchronous);
+ if (err)
+ return err;
+
+ err = _gpgme_op_verify_init_result (ctx);
+ if (err)
+ return err;
+
+ _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx);
+
+ if (!sig)
+ return gpg_error (GPG_ERR_NO_DATA);
+ if (!signed_text && !plaintext)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext);
+}
+
+
+/* Decrypt ciphertext CIPHER and make a signature verification within
+ CTX and store the resulting plaintext in PLAIN. */
+gpgme_error_t
+gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig,
+ gpgme_data_t signed_text, gpgme_data_t plaintext)
+{
+ return verify_start (ctx, 0, sig, signed_text, plaintext);
+}
+
+
+/* Decrypt ciphertext CIPHER and make a signature verification within
+ CTX and store the resulting plaintext in PLAIN. */
+gpgme_error_t
+gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text,
+ gpgme_data_t plaintext)
+{
+ gpgme_error_t err;
+
+ err = verify_start (ctx, 1, sig, signed_text, plaintext);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+/* Compatibility interfaces. */
+
+/* Get the key used to create signature IDX in CTX and return it in
+ R_KEY. */
+gpgme_error_t
+gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
+{
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+
+ result = gpgme_op_verify_result (ctx);
+ sig = result->signatures;
+
+ while (sig && idx)
+ {
+ sig = sig->next;
+ idx--;
+ }
+ if (!sig || idx)
+ return gpg_error (GPG_ERR_EOF);
+
+ return gpgme_get_key (ctx, sig->fpr, r_key, 0);
+}
+
+
+/* Retrieve the signature status of signature IDX in CTX after a
+ successful verify operation in R_STAT (if non-null). The creation
+ time stamp of the signature is returned in R_CREATED (if non-null).
+ The function returns a string containing the fingerprint. */
+const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
+ _gpgme_sig_stat_t *r_stat, time_t *r_created)
+{
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+
+ result = gpgme_op_verify_result (ctx);
+ sig = result->signatures;
+
+ while (sig && idx)
+ {
+ sig = sig->next;
+ idx--;
+ }
+ if (!sig || idx)
+ return NULL;
+
+ if (r_stat)
+ {
+ switch (gpg_err_code (sig->status))
+ {
+ case GPG_ERR_NO_ERROR:
+ *r_stat = GPGME_SIG_STAT_GOOD;
+ break;
+
+ case GPG_ERR_BAD_SIGNATURE:
+ *r_stat = GPGME_SIG_STAT_BAD;
+ break;
+
+ case GPG_ERR_NO_PUBKEY:
+ *r_stat = GPGME_SIG_STAT_NOKEY;
+ break;
+
+ case GPG_ERR_NO_DATA:
+ *r_stat = GPGME_SIG_STAT_NOSIG;
+ break;
+
+ case GPG_ERR_SIG_EXPIRED:
+ *r_stat = GPGME_SIG_STAT_GOOD_EXP;
+ break;
+
+ case GPG_ERR_KEY_EXPIRED:
+ *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
+ break;
+
+ default:
+ *r_stat = GPGME_SIG_STAT_ERROR;
+ break;
+ }
+ }
+ if (r_created)
+ *r_created = sig->timestamp;
+ return sig->fpr;
+}
+
+
+/* Retrieve certain attributes of a signature. IDX is the index
+ number of the signature after a successful verify operation. WHAT
+ is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
+ one. WHATIDX is to be passed as 0 for most attributes . */
+unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
+ _gpgme_attr_t what, int whatidx)
+{
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+
+ result = gpgme_op_verify_result (ctx);
+ sig = result->signatures;
+
+ while (sig && idx)
+ {
+ sig = sig->next;
+ idx--;
+ }
+ if (!sig || idx)
+ return 0;
+
+ switch (what)
+ {
+ case GPGME_ATTR_CREATED:
+ return sig->timestamp;
+
+ case GPGME_ATTR_EXPIRE:
+ return sig->exp_timestamp;
+
+ case GPGME_ATTR_VALIDITY:
+ return (unsigned long) sig->validity;
+
+ case GPGME_ATTR_SIG_STATUS:
+ switch (gpg_err_code (sig->status))
+ {
+ case GPG_ERR_NO_ERROR:
+ return GPGME_SIG_STAT_GOOD;
+
+ case GPG_ERR_BAD_SIGNATURE:
+ return GPGME_SIG_STAT_BAD;
+
+ case GPG_ERR_NO_PUBKEY:
+ return GPGME_SIG_STAT_NOKEY;
+
+ case GPG_ERR_NO_DATA:
+ return GPGME_SIG_STAT_NOSIG;
+
+ case GPG_ERR_SIG_EXPIRED:
+ return GPGME_SIG_STAT_GOOD_EXP;
+
+ case GPG_ERR_KEY_EXPIRED:
+ return GPGME_SIG_STAT_GOOD_EXPKEY;
+
+ default:
+ return GPGME_SIG_STAT_ERROR;
+ }
+
+ case GPGME_ATTR_SIG_SUMMARY:
+ return sig->summary;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+const char *gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
+ _gpgme_attr_t what, int whatidx)
+{
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+
+ result = gpgme_op_verify_result (ctx);
+ sig = result->signatures;
+
+ while (sig && idx)
+ {
+ sig = sig->next;
+ idx--;
+ }
+ if (!sig || idx)
+ return NULL;
+
+ switch (what)
+ {
+ case GPGME_ATTR_FPR:
+ return sig->fpr;
+
+ case GPGME_ATTR_ERRTOK:
+ if (whatidx == 1)
+ return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
+ else
+ return "";
+ default:
+ break;
+ }
+
+ return NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/version.c b/branches/gpgme-1-0-branch/gpgme/version.c
new file mode 100644
index 00000000..e2c4ef81
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/version.c
@@ -0,0 +1,219 @@
+/* version.c - Version check routines.
+ 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 <string.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "gpgme.h"
+#include "io.h"
+
+/* For _gpgme_sema_subsystem_init (). */
+#include "sema.h"
+
+
+/* Bootstrap the subsystems needed for concurrent operation. This
+ must be done once at startup. We can not guarantee this using a
+ lock, though, because the semaphore subsystem needs to be
+ initialized itself before it can be used. So we expect that the
+ user performs the necessary syncrhonization. */
+static void
+do_subsystem_inits (void)
+{
+ static int done = 0;
+
+ if (done)
+ return;
+
+ _gpgme_sema_subsystem_init ();
+ _gpgme_io_subsystem_init ();
+
+ done = 1;
+}
+
+
+/* Read the next number in the version string STR and return it in
+ *NUMBER. Return a pointer to the tail of STR after parsing, or
+ *NULL if the version string was invalid. */
+static const char *
+parse_version_number (const char *str, int *number)
+{
+#define MAXVAL ((INT_MAX - 10) / 10)
+ int val = 0;
+
+ /* Leading zeros are not allowed. */
+ if (*str == '0' && isdigit(str[1]))
+ return NULL;
+
+ while (isdigit (*str) && val <= MAXVAL)
+ {
+ val *= 10;
+ val += *(str++) - '0';
+ }
+ *number = val;
+ return val > MAXVAL ? NULL : str;
+}
+
+
+/* Parse the version string STR in the format MAJOR.MINOR.MICRO (for
+ example, 9.3.2) and return the components in MAJOR, MINOR and MICRO
+ as integers. The function returns the tail of the string that
+ follows the version number. This might be te empty string if there
+ is nothing following the version number, or a patchlevel. The
+ function returns NULL if the version string is not valid. */
+static const char *
+parse_version_string (const char *str, int *major, int *minor, int *micro)
+{
+ str = parse_version_number (str, major);
+ if (!str || *str != '.')
+ return NULL;
+ str++;
+
+ str = parse_version_number (str, minor);
+ if (!str || *str != '.')
+ return NULL;
+ str++;
+
+ str = parse_version_number (str, micro);
+ if (!str)
+ return NULL;
+
+ /* A patchlevel might follow. */
+ return str;
+}
+
+
+const char *
+_gpgme_compare_versions (const char *my_version,
+ const char *rq_version)
+{
+ int my_major, my_minor, my_micro;
+ int rq_major, rq_minor, rq_micro;
+ const char *my_plvl, *rq_plvl;
+
+ if (!rq_version)
+ return my_version;
+ if (!my_version)
+ return NULL;
+
+ my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
+ if (!my_plvl)
+ return NULL;
+
+ rq_plvl = parse_version_string (rq_version, &rq_major, &rq_minor, &rq_micro);
+ if (!rq_plvl)
+ return NULL;
+
+ if (my_major > rq_major
+ || (my_major == rq_major && my_minor > rq_minor)
+ || (my_major == rq_major && my_minor == rq_minor
+ && my_micro > rq_micro)
+ || (my_major == rq_major && my_minor == rq_minor
+ && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
+ return my_version;
+
+ return NULL;
+}
+
+
+/* Check that the the version of the library is at minimum the
+ requested one and return the version string; return NULL if the
+ condition is not met. If a NULL is passed to this function, no
+ check is done and the version string is simply returned.
+
+ This function must be run once at startup, as it also initializes
+ some subsystems. Its invocation must be synchronized against
+ calling any of the other functions in a multi-threaded
+ environments. */
+const char *
+gpgme_check_version (const char *req_version)
+{
+ do_subsystem_inits ();
+ return _gpgme_compare_versions (VERSION, req_version);
+}
+
+
+#define LINELENGTH 80
+
+/* Retrieve the version number from the --version output of the
+ program FILE_NAME. */
+char *
+_gpgme_get_program_version (const char *const file_name)
+{
+ char line[LINELENGTH] = "";
+ int linelen = 0;
+ char *mark = NULL;
+ int rp[2];
+ int nread;
+ char *argv[] = {NULL /* file_name */, "--version", 0};
+ struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
+ struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
+ int status;
+
+ if (!file_name)
+ return NULL;
+ argv[0] = (char *) file_name;
+
+ if (_gpgme_io_pipe (rp, 1) < 0)
+ return NULL;
+
+ pfd[0].fd = rp[1];
+ cfd[0].fd = rp[1];
+
+ status = _gpgme_io_spawn (file_name, argv, cfd, pfd);
+ if (status < 0)
+ {
+ _gpgme_io_close (rp[0]);
+ _gpgme_io_close (rp[1]);
+ return NULL;
+ }
+
+ do
+ {
+ nread = _gpgme_io_read (rp[0], &line[linelen], LINELENGTH - linelen - 1);
+ if (nread > 0)
+ {
+ line[linelen + nread] = '\0';
+ mark = strchr (&line[linelen], '\n');
+ if (mark)
+ {
+ *mark = '\0';
+ break;
+ }
+ linelen += nread;
+ }
+ }
+ while (nread > 0 && linelen < LINELENGTH - 1);
+
+ _gpgme_io_close (rp[0]);
+
+ if (mark)
+ {
+ mark = strrchr (line, ' ');
+ if (!mark)
+ return NULL;
+ return strdup (mark + 1);
+ }
+
+ return NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/w32-io.c b/branches/gpgme-1-0-branch/gpgme/w32-io.c
new file mode 100644
index 00000000..24082bd1
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/w32-io.c
@@ -0,0 +1,1117 @@
+/* w32-io.c - W32 API I/O functions.
+ 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <windows.h>
+#include <io.h>
+
+#include "util.h"
+#include "sema.h"
+#include "io.h"
+
+
+/* We assume that a HANDLE can be represented by an int which should
+ be true for all i386 systems (HANDLE is defined as void *) and
+ these are the only systems for which Windows is available. Further
+ we assume that -1 denotes an invalid handle. */
+
+#define fd_to_handle(a) ((HANDLE)(a))
+#define handle_to_fd(a) ((int)(a))
+#define pid_to_handle(a) ((HANDLE)(a))
+#define handle_to_pid(a) ((int)(a))
+
+#define READBUF_SIZE 4096
+#define WRITEBUF_SIZE 4096
+#define MAX_READERS 20
+#define MAX_WRITERS 20
+
+static struct {
+ int inuse;
+ int fd;
+ void (*handler)(int,void*);
+ void *value;
+} notify_table[256];
+DEFINE_STATIC_LOCK (notify_table_lock);
+
+
+struct reader_context_s {
+ HANDLE file_hd;
+ HANDLE thread_hd;
+ DECLARE_LOCK (mutex);
+
+ int stop_me;
+ int eof;
+ int eof_shortcut;
+ int error;
+ int error_code;
+
+ HANDLE have_data_ev; /* manually reset */
+ HANDLE have_space_ev; /* auto reset */
+ HANDLE stopped;
+ size_t readpos, writepos;
+ char buffer[READBUF_SIZE];
+};
+
+
+static struct {
+ volatile int used;
+ int fd;
+ struct reader_context_s *context;
+} reader_table[MAX_READERS];
+static int reader_table_size= MAX_READERS;
+DEFINE_STATIC_LOCK (reader_table_lock);
+
+
+struct writer_context_s {
+ HANDLE file_hd;
+ HANDLE thread_hd;
+ DECLARE_LOCK (mutex);
+
+ int stop_me;
+ int error;
+ int error_code;
+
+ HANDLE have_data; /* manually reset */
+ HANDLE is_empty;
+ HANDLE stopped;
+ size_t nbytes;
+ char buffer[WRITEBUF_SIZE];
+};
+
+
+static struct {
+ volatile int used;
+ int fd;
+ struct writer_context_s *context;
+} writer_table[MAX_WRITERS];
+static int writer_table_size= MAX_WRITERS;
+DEFINE_STATIC_LOCK (writer_table_lock);
+
+
+
+static HANDLE
+set_synchronize (HANDLE h)
+{
+ HANDLE tmp;
+
+ /* For NT we have to set the sync flag. It seems that the only
+ * way to do it is by duplicating the handle. Tsss.. */
+ if (!DuplicateHandle( GetCurrentProcess(), h,
+ GetCurrentProcess(), &tmp,
+ EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, 0 ) ) {
+ DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError());
+ }
+ else {
+ CloseHandle (h);
+ h = tmp;
+ }
+ return h;
+}
+
+
+
+static DWORD CALLBACK
+reader (void *arg)
+{
+ struct reader_context_s *c = arg;
+ int nbytes;
+ DWORD nread;
+
+ DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd );
+ for (;;) {
+ LOCK (c->mutex);
+ /* leave a 1 byte gap so that we can see whether it is empty or full*/
+ if ((c->writepos + 1) % READBUF_SIZE == c->readpos) {
+ /* wait for space */
+ if (!ResetEvent (c->have_space_ev) )
+ DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
+ UNLOCK (c->mutex);
+ DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd );
+ WaitForSingleObject (c->have_space_ev, INFINITE);
+ DEBUG1 ("reader thread %p: got space", c->thread_hd );
+ LOCK (c->mutex);
+ }
+ if ( c->stop_me ) {
+ UNLOCK (c->mutex);
+ break;
+ }
+ nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE;
+ if ( nbytes > READBUF_SIZE - c->writepos )
+ nbytes = READBUF_SIZE - c->writepos;
+ UNLOCK (c->mutex);
+
+ DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes );
+ if ( !ReadFile ( c->file_hd,
+ c->buffer+c->writepos, nbytes, &nread, NULL) ) {
+ c->error_code = (int)GetLastError ();
+ if (c->error_code == ERROR_BROKEN_PIPE ) {
+ c->eof=1;
+ DEBUG1 ("reader thread %p: got eof (broken pipe)",
+ c->thread_hd );
+ }
+ else {
+ c->error = 1;
+ DEBUG2 ("reader thread %p: read error: ec=%d",
+ c->thread_hd, c->error_code );
+ }
+ break;
+ }
+ if ( !nread ) {
+ c->eof = 1;
+ DEBUG1 ("reader thread %p: got eof", c->thread_hd );
+ break;
+ }
+ DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread );
+
+ LOCK (c->mutex);
+ if (c->stop_me) {
+ UNLOCK (c->mutex);
+ break;
+ }
+ c->writepos = (c->writepos + nread) % READBUF_SIZE;
+ if ( !SetEvent (c->have_data_ev) )
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ UNLOCK (c->mutex);
+ }
+ /* indicate that we have an error or eof */
+ if ( !SetEvent (c->have_data_ev) )
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ DEBUG1 ("reader thread %p ended", c->thread_hd );
+ SetEvent (c->stopped);
+
+ return 0;
+}
+
+
+static struct reader_context_s *
+create_reader (HANDLE fd)
+{
+ struct reader_context_s *c;
+ SECURITY_ATTRIBUTES sec_attr;
+ DWORD tid;
+
+ DEBUG1 ("creating new read thread for file handle %p", fd );
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ c = calloc (1, sizeof *c );
+ if (!c)
+ return NULL;
+
+ c->file_hd = fd;
+ c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+ c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL);
+ c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+ if (!c->have_data_ev || !c->have_space_ev || !c->stopped ) {
+ DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
+ if (c->have_data_ev)
+ CloseHandle (c->have_data_ev);
+ if (c->have_space_ev)
+ CloseHandle (c->have_space_ev);
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ free (c);
+ return NULL;
+ }
+
+ c->have_data_ev = set_synchronize (c->have_data_ev);
+ INIT_LOCK (c->mutex);
+
+ c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid );
+ if (!c->thread_hd) {
+ DEBUG1 ("** failed to create reader thread: ec=%d\n",
+ (int)GetLastError ());
+ DESTROY_LOCK (c->mutex);
+ if (c->have_data_ev)
+ CloseHandle (c->have_data_ev);
+ if (c->have_space_ev)
+ CloseHandle (c->have_space_ev);
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ free (c);
+ return NULL;
+ }
+
+ return c;
+}
+
+static void
+destroy_reader (struct reader_context_s *c)
+{
+ LOCK (c->mutex);
+ c->stop_me = 1;
+ if (c->have_space_ev)
+ SetEvent (c->have_space_ev);
+ UNLOCK (c->mutex);
+
+ DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
+ WaitForSingleObject (c->stopped, INFINITE);
+ DEBUG1 ("thread %p has terminated", c->thread_hd );
+
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ if (c->have_data_ev)
+ CloseHandle (c->have_data_ev);
+ if (c->have_space_ev)
+ CloseHandle (c->have_space_ev);
+ CloseHandle (c->thread_hd);
+ DESTROY_LOCK (c->mutex);
+ free (c);
+}
+
+
+/*
+ * Find a reader context or create a new one
+ * Note that the reader context will last until a io_close.
+ */
+static struct reader_context_s *
+find_reader (int fd, int start_it)
+{
+ int i;
+
+ for (i=0; i < reader_table_size ; i++ ) {
+ if ( reader_table[i].used && reader_table[i].fd == fd )
+ return reader_table[i].context;
+ }
+ if (!start_it)
+ return NULL;
+
+ LOCK (reader_table_lock);
+ for (i=0; i < reader_table_size; i++ ) {
+ if (!reader_table[i].used) {
+ reader_table[i].fd = fd;
+ reader_table[i].context = create_reader (fd_to_handle (fd));
+ reader_table[i].used = 1;
+ UNLOCK (reader_table_lock);
+ return reader_table[i].context;
+ }
+ }
+ UNLOCK (reader_table_lock);
+ return NULL;
+}
+
+
+static void
+kill_reader (int fd)
+{
+ int i;
+
+ LOCK (reader_table_lock);
+ for (i=0; i < reader_table_size; i++ ) {
+ if (reader_table[i].used && reader_table[i].fd == fd ) {
+ destroy_reader (reader_table[i].context);
+ reader_table[i].context = NULL;
+ reader_table[i].used = 0;
+ break;
+ }
+ }
+ UNLOCK (reader_table_lock);
+}
+
+
+
+int
+_gpgme_io_read ( int fd, void *buffer, size_t count )
+{
+ int nread;
+ struct reader_context_s *c = find_reader (fd,1);
+
+ DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count );
+ if ( !c ) {
+ DEBUG0 ( "no reader thread\n");
+ return -1;
+ }
+ if (c->eof_shortcut) {
+ DEBUG1 ("fd %d: EOF (again)", fd );
+ return 0;
+ }
+
+ LOCK (c->mutex);
+ if (c->readpos == c->writepos && !c->error) { /*no data avail*/
+ UNLOCK (c->mutex);
+ DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd);
+ WaitForSingleObject (c->have_data_ev, INFINITE);
+ DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd);
+ LOCK (c->mutex);
+ }
+
+ if (c->readpos == c->writepos || c->error) {
+ UNLOCK (c->mutex);
+ c->eof_shortcut = 1;
+ if (c->eof) {
+ DEBUG1 ("fd %d: EOF", fd );
+ return 0;
+ }
+ if (!c->error) {
+ DEBUG1 ("fd %d: EOF but eof flag not set", fd );
+ return 0;
+ }
+ DEBUG1 ("fd %d: read error", fd );
+ return -1;
+ }
+
+ nread = c->readpos < c->writepos? c->writepos - c->readpos
+ : READBUF_SIZE - c->readpos;
+ if (nread > count)
+ nread = count;
+ memcpy (buffer, c->buffer+c->readpos, nread);
+ c->readpos = (c->readpos + nread) % READBUF_SIZE;
+ if (c->readpos == c->writepos && !c->eof) {
+ if ( !ResetEvent (c->have_data_ev) )
+ DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
+ }
+ if (!SetEvent (c->have_space_ev))
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ UNLOCK (c->mutex);
+
+ DEBUG2 ("fd %d: got %d bytes\n", fd, nread );
+
+ return nread;
+}
+
+
+
+/*
+ * The writer does use a simple buffering strategy so that we are
+ * informed about write errors as soon as possible (i.e. with the the
+ * next call to the write function
+ */
+static DWORD CALLBACK
+writer (void *arg)
+{
+ struct writer_context_s *c = arg;
+ DWORD nwritten;
+
+ DEBUG2 ("writer thread %p for file %p started", c->thread_hd, c->file_hd );
+ for (;;) {
+ LOCK (c->mutex);
+ if ( !c->nbytes ) {
+ if (!ResetEvent (c->have_data) )
+ DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ());
+ UNLOCK (c->mutex);
+ DEBUG1 ("writer thread %p: idle ...", c->thread_hd );
+ WaitForSingleObject (c->have_data, INFINITE);
+ DEBUG1 ("writer thread %p: got data to send", c->thread_hd );
+ LOCK (c->mutex);
+ }
+ if ( c->stop_me ) {
+ UNLOCK (c->mutex);
+ break;
+ }
+ UNLOCK (c->mutex);
+
+ DEBUG2 ("writer thread %p: writing %d bytes",
+ c->thread_hd, c->nbytes );
+ if ( c->nbytes && !WriteFile ( c->file_hd, c->buffer, c->nbytes,
+ &nwritten, NULL)) {
+ c->error_code = (int)GetLastError ();
+ c->error = 1;
+ DEBUG2 ("writer thread %p: write error: ec=%d",
+ c->thread_hd, c->error_code );
+ break;
+ }
+ DEBUG2 ("writer thread %p: wrote %d bytes",
+ c->thread_hd, (int)nwritten );
+
+ LOCK (c->mutex);
+ c->nbytes -= nwritten;
+ if (c->stop_me) {
+ UNLOCK (c->mutex);
+ break;
+ }
+ if ( !c->nbytes ) {
+ if ( !SetEvent (c->is_empty) )
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ }
+ UNLOCK (c->mutex);
+ }
+ /* indicate that we have an error */
+ if ( !SetEvent (c->is_empty) )
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ DEBUG1 ("writer thread %p ended", c->thread_hd );
+ SetEvent (c->stopped);
+
+ return 0;
+}
+
+
+static struct writer_context_s *
+create_writer (HANDLE fd)
+{
+ struct writer_context_s *c;
+ SECURITY_ATTRIBUTES sec_attr;
+ DWORD tid;
+
+ DEBUG1 ("creating new write thread for file handle %p", fd );
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ c = calloc (1, sizeof *c );
+ if (!c)
+ return NULL;
+
+ c->file_hd = fd;
+ c->have_data = CreateEvent (&sec_attr, FALSE, FALSE, NULL);
+ c->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL);
+ c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL);
+ if (!c->have_data || !c->is_empty || !c->stopped ) {
+ DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ());
+ if (c->have_data)
+ CloseHandle (c->have_data);
+ if (c->is_empty)
+ CloseHandle (c->is_empty);
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ free (c);
+ return NULL;
+ }
+
+ c->is_empty = set_synchronize (c->is_empty);
+ INIT_LOCK (c->mutex);
+
+ c->thread_hd = CreateThread (&sec_attr, 0, writer, c, 0, &tid );
+ if (!c->thread_hd) {
+ DEBUG1 ("** failed to create writer thread: ec=%d\n",
+ (int)GetLastError ());
+ DESTROY_LOCK (c->mutex);
+ if (c->have_data)
+ CloseHandle (c->have_data);
+ if (c->is_empty)
+ CloseHandle (c->is_empty);
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ free (c);
+ return NULL;
+ }
+
+ return c;
+}
+
+static void
+destroy_writer (struct writer_context_s *c)
+{
+ LOCK (c->mutex);
+ c->stop_me = 1;
+ if (c->have_data)
+ SetEvent (c->have_data);
+ UNLOCK (c->mutex);
+
+ DEBUG1 ("waiting for thread %p termination ...", c->thread_hd );
+ WaitForSingleObject (c->stopped, INFINITE);
+ DEBUG1 ("thread %p has terminated", c->thread_hd );
+
+ if (c->stopped)
+ CloseHandle (c->stopped);
+ if (c->have_data)
+ CloseHandle (c->have_data);
+ if (c->is_empty)
+ CloseHandle (c->is_empty);
+ CloseHandle (c->thread_hd);
+ DESTROY_LOCK (c->mutex);
+ free (c);
+}
+
+
+/*
+ * Find a writer context or create a new one
+ * Note that the writer context will last until a io_close.
+ */
+static struct writer_context_s *
+find_writer (int fd, int start_it)
+{
+ int i;
+
+ for (i=0; i < writer_table_size ; i++ ) {
+ if ( writer_table[i].used && writer_table[i].fd == fd )
+ return writer_table[i].context;
+ }
+ if (!start_it)
+ return NULL;
+
+ LOCK (writer_table_lock);
+ for (i=0; i < writer_table_size; i++ ) {
+ if (!writer_table[i].used) {
+ writer_table[i].fd = fd;
+ writer_table[i].context = create_writer (fd_to_handle (fd));
+ writer_table[i].used = 1;
+ UNLOCK (writer_table_lock);
+ return writer_table[i].context;
+ }
+ }
+ UNLOCK (writer_table_lock);
+ return NULL;
+}
+
+
+static void
+kill_writer (int fd)
+{
+ int i;
+
+ LOCK (writer_table_lock);
+ for (i=0; i < writer_table_size; i++ ) {
+ if (writer_table[i].used && writer_table[i].fd == fd ) {
+ destroy_writer (writer_table[i].context);
+ writer_table[i].context = NULL;
+ writer_table[i].used = 0;
+ break;
+ }
+ }
+ UNLOCK (writer_table_lock);
+}
+
+
+
+
+int
+_gpgme_io_write ( int fd, const void *buffer, size_t count )
+{
+ struct writer_context_s *c = find_writer (fd,1);
+
+ DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count );
+ if ( !c ) {
+ DEBUG0 ( "no writer thread\n");
+ return -1;
+ }
+
+ LOCK (c->mutex);
+ if ( c->nbytes ) { /* bytes are pending for send */
+ UNLOCK (c->mutex);
+ DEBUG2 ("fd %d: waiting for empty buffer in thread %p",
+ fd, c->thread_hd);
+ WaitForSingleObject (c->is_empty, INFINITE);
+ DEBUG2 ("fd %d: thread %p buffer is empty", fd, c->thread_hd);
+ assert (!c->nbytes);
+ LOCK (c->mutex);
+ }
+
+ if ( c->error) {
+ UNLOCK (c->mutex);
+ DEBUG1 ("fd %d: write error", fd );
+ return -1;
+ }
+
+ if (count > WRITEBUF_SIZE)
+ count = WRITEBUF_SIZE;
+ memcpy (c->buffer, buffer, count);
+ c->nbytes = count;
+ if (!SetEvent (c->have_data))
+ DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ());
+ UNLOCK (c->mutex);
+
+ DEBUG2 ("fd %d: copied %d bytes\n",
+ fd, (int)count );
+ return (int)count;
+}
+
+
+int
+_gpgme_io_pipe ( int filedes[2], int inherit_idx )
+{
+ HANDLE r, w;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ if (!CreatePipe ( &r, &w, &sec_attr, 0))
+ return -1;
+ /* make one end inheritable */
+ if ( inherit_idx == 0 ) {
+ HANDLE h;
+ if (!DuplicateHandle( GetCurrentProcess(), r,
+ GetCurrentProcess(), &h, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ) ) {
+ DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+ }
+ CloseHandle (r);
+ r = h;
+ }
+ else if ( inherit_idx == 1 ) {
+ HANDLE h;
+ if (!DuplicateHandle( GetCurrentProcess(), w,
+ GetCurrentProcess(), &h, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ) ) {
+ DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError());
+ CloseHandle (r);
+ CloseHandle (w);
+ return -1;
+ }
+ CloseHandle (w);
+ w = h;
+ }
+
+ filedes[0] = handle_to_fd (r);
+ filedes[1] = handle_to_fd (w);
+ DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w,
+ filedes[0], filedes[1], inherit_idx );
+ return 0;
+}
+
+int
+_gpgme_io_close ( int fd )
+{
+ int i;
+ void (*handler)(int, void*) = NULL;
+ void *value = NULL;
+
+ if ( fd == -1 )
+ return -1;
+
+ DEBUG1 ("** closing handle for fd %d\n", fd);
+ kill_reader (fd);
+ kill_writer (fd);
+ LOCK (notify_table_lock);
+ for ( i=0; i < DIM (notify_table); i++ ) {
+ if (notify_table[i].inuse && notify_table[i].fd == fd) {
+ handler = notify_table[i].handler;
+ value = notify_table[i].value;
+ notify_table[i].handler = NULL;
+ notify_table[i].value = NULL;
+ notify_table[i].inuse = 0;
+ break;
+ }
+ }
+ UNLOCK (notify_table_lock);
+ if (handler)
+ handler (fd, value);
+
+ if ( !CloseHandle (fd_to_handle (fd)) ) {
+ DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n",
+ fd, (int)GetLastError ());
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+_gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
+{
+ int i;
+
+ assert (fd != -1);
+
+ LOCK (notify_table_lock);
+ for (i=0; i < DIM (notify_table); i++ ) {
+ if ( notify_table[i].inuse && notify_table[i].fd == fd )
+ break;
+ }
+ if ( i == DIM (notify_table) ) {
+ for (i=0; i < DIM (notify_table); i++ ) {
+ if ( !notify_table[i].inuse )
+ break;
+ }
+ }
+ if ( i == DIM (notify_table) ) {
+ UNLOCK (notify_table_lock);
+ return -1;
+ }
+ notify_table[i].fd = fd;
+ notify_table[i].handler = handler;
+ notify_table[i].value = value;
+ notify_table[i].inuse = 1;
+ UNLOCK (notify_table_lock);
+ DEBUG2 ("set notification for fd %d (idx=%d)", fd, i );
+ return 0;
+}
+
+
+int
+_gpgme_io_set_nonblocking ( int fd )
+{
+ return 0;
+}
+
+
+static char *
+build_commandline ( char **argv )
+{
+ int i, n = 0;
+ char *buf, *p;
+
+ /* FIXME: we have to quote some things because under Windows the
+ * program parses the commandline and does some unquoting */
+ for (i=0; argv[i]; i++)
+ n += strlen (argv[i]) + 2 + 1; /* 2 extra bytes for possible quoting */
+ buf = p = malloc (n);
+ if ( !buf )
+ return NULL;
+ *buf = 0;
+ if ( argv[0] )
+ p = stpcpy (p, argv[0]);
+ for (i = 1; argv[i]; i++) {
+ if (!*argv[i])
+ p = stpcpy (p, " \"\"");
+ else
+ p = stpcpy (stpcpy (p, " "), argv[i]);
+ }
+
+ return buf;
+}
+
+
+int
+_gpgme_io_spawn ( const char *path, char **argv,
+ struct spawn_fd_item_s *fd_child_list,
+ struct spawn_fd_item_s *fd_parent_list )
+{
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = {
+ NULL, /* returns process handle */
+ 0, /* returns primary thread handle */
+ 0, /* returns pid */
+ 0 /* returns tid */
+ };
+ STARTUPINFO si;
+ char *envblock = NULL;
+ int cr_flags = CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ());
+ int i;
+ char *arg_string;
+ int duped_stdin = 0;
+ int duped_stderr = 0;
+ HANDLE hnul = INVALID_HANDLE_VALUE;
+ /* FIXME. */
+ int debug_me = 0;
+
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ arg_string = build_commandline ( argv );
+ if (!arg_string )
+ return -1;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = debug_me? SW_SHOW : SW_MINIMIZE;
+ si.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
+ si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
+ si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+
+ for (i=0; fd_child_list[i].fd != -1; i++ ) {
+ if (fd_child_list[i].dup_to == 0 ) {
+ si.hStdInput = fd_to_handle (fd_child_list[i].fd);
+ DEBUG1 ("using %d for stdin", fd_child_list[i].fd );
+ duped_stdin=1;
+ }
+ else if (fd_child_list[i].dup_to == 1 ) {
+ si.hStdOutput = fd_to_handle (fd_child_list[i].fd);
+ DEBUG1 ("using %d for stdout", fd_child_list[i].fd );
+ }
+ else if (fd_child_list[i].dup_to == 2 ) {
+ si.hStdError = fd_to_handle (fd_child_list[i].fd);
+ DEBUG1 ("using %d for stderr", fd_child_list[i].fd );
+ duped_stderr = 1;
+ }
+ }
+
+ if( !duped_stdin || !duped_stderr ) {
+ SECURITY_ATTRIBUTES sa;
+
+ memset (&sa, 0, sizeof sa );
+ sa.nLength = sizeof sa;
+ sa.bInheritHandle = TRUE;
+ hnul = CreateFile ( "nul",
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if ( hnul == INVALID_HANDLE_VALUE ) {
+ DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ());
+ free (arg_string);
+ return -1;
+ }
+ /* Make sure that the process has a connected stdin */
+ if ( !duped_stdin ) {
+ si.hStdInput = hnul;
+ DEBUG1 ("using %d for dummy stdin", (int)hnul );
+ }
+ /* We normally don't want all the normal output */
+ if ( !duped_stderr ) {
+ si.hStdError = hnul;
+ DEBUG1 ("using %d for dummy stderr", (int)hnul );
+ }
+ }
+
+ DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string);
+ cr_flags |= CREATE_SUSPENDED;
+ if ( !CreateProcessA (path,
+ arg_string,
+ &sec_attr, /* process security attributes */
+ &sec_attr, /* thread security attributes */
+ TRUE, /* inherit handles */
+ cr_flags, /* creation flags */
+ envblock, /* environment */
+ NULL, /* use current drive/directory */
+ &si, /* startup information */
+ &pi /* returns process information */
+ ) ) {
+ DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ());
+ free (arg_string);
+ return -1;
+ }
+
+ /* close the /dev/nul handle if used */
+ if (hnul != INVALID_HANDLE_VALUE ) {
+ if ( !CloseHandle ( hnul ) )
+ DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError());
+ }
+
+ /* Close the other ends of the pipes */
+ for (i = 0; fd_parent_list[i].fd != -1; i++)
+ _gpgme_io_close (fd_parent_list[i].fd);
+
+ DEBUG4 ("CreateProcess ready\n"
+ "- hProcess=%p hThread=%p\n"
+ "- dwProcessID=%d dwThreadId=%d\n",
+ pi.hProcess, pi.hThread,
+ (int) pi.dwProcessId, (int) pi.dwThreadId);
+
+ if ( ResumeThread ( pi.hThread ) < 0 ) {
+ DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ());
+ }
+
+ if ( !CloseHandle (pi.hThread) ) {
+ DEBUG1 ("CloseHandle of thread failed: ec=%d\n",
+ (int)GetLastError ());
+ }
+
+ return handle_to_pid (pi.hProcess);
+}
+
+
+
+
+int
+_gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
+{
+ HANDLE proc = fd_to_handle (pid);
+ int code, ret = 0;
+ DWORD exc;
+
+ *r_status = 0;
+ *r_signal = 0;
+ code = WaitForSingleObject ( proc, hang? INFINITE : 0 );
+ switch (code) {
+ case WAIT_FAILED:
+ DEBUG2 ("WFSO pid=%d failed: %d\n", (int)pid, (int)GetLastError () );
+ break;
+
+ case WAIT_OBJECT_0:
+ if (!GetExitCodeProcess (proc, &exc)) {
+ DEBUG2 ("** GECP pid=%d failed: ec=%d\n",
+ (int)pid, (int)GetLastError () );
+ *r_status = 4;
+ }
+ else {
+ DEBUG2 ("GECP pid=%d exit code=%d\n", (int)pid, exc);
+ *r_status = exc;
+ }
+ ret = 1;
+ break;
+
+ case WAIT_TIMEOUT:
+ if (hang)
+ DEBUG1 ("WFSO pid=%d timed out\n", (int)pid);
+ break;
+
+ default:
+ DEBUG2 ("WFSO pid=%d returned %d\n", (int)pid, code );
+ break;
+ }
+ return ret;
+}
+
+int
+_gpgme_io_kill ( int pid, int hard )
+{
+ HANDLE proc = fd_to_handle (pid);
+
+ #warning I am not sure how to kill a process
+ /* fixme: figure out how this can be done */
+ return 0;
+}
+
+
+
+/*
+ * Select on the list of fds.
+ * Returns: -1 = error
+ * 0 = timeout or nothing to select
+ * >0 = number of signaled fds
+ */
+int
+_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock )
+{
+ HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS];
+ int waitidx[MAXIMUM_WAIT_OBJECTS];
+ int code, nwait;
+ int i, any;
+ int count;
+ void *dbg_help;
+
+ restart:
+ DEBUG_BEGIN (dbg_help, 3, "select on [ ");
+ any = 0;
+ nwait = 0;
+ count = 0;
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ fds[i].signaled = 0;
+ if ( fds[i].for_read || fds[i].for_write ) {
+ if ( fds[i].frozen ) {
+ DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
+ }
+ else if ( fds[i].for_read ) {
+ struct reader_context_s *c = find_reader (fds[i].fd,1);
+
+ if (!c) {
+ DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd);
+ }
+ else {
+ if ( nwait >= DIM (waitbuf) ) {
+ DEBUG_END (dbg_help, "oops ]");
+ DEBUG0 ("Too many objects for WFMO!" );
+ return -1;
+ }
+ waitidx[nwait] = i;
+ waitbuf[nwait++] = c->have_data_ev;
+ }
+ DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd );
+ any = 1;
+ }
+ else if ( fds[i].for_write ) {
+ struct writer_context_s *c = find_writer (fds[i].fd,1);
+
+ if (!c) {
+ DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd);
+ }
+ else {
+ if ( nwait >= DIM (waitbuf) ) {
+ DEBUG_END (dbg_help, "oops ]");
+ DEBUG0 ("Too many objects for WFMO!" );
+ return -1;
+ }
+ LOCK (c->mutex);
+ if ( !c->nbytes ) {
+ waitidx[nwait] = i;
+ waitbuf[nwait++] = c->is_empty;
+ DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd );
+ any = 1;
+ }
+ else {
+ DEBUG_ADD1 (dbg_help, "w%d(ignored) ", fds[i].fd );
+ }
+ UNLOCK (c->mutex);
+ }
+ }
+ }
+ }
+ DEBUG_END (dbg_help, "]");
+ if (!any)
+ return 0;
+
+ code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000);
+ if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) {
+ /* This WFMO is a really silly function: It does return either
+ * the index of the signaled object or if 2 objects have been
+ * signalled at the same time, the index of the object with the
+ * lowest object is returned - so and how do we find out
+ * how many objects have been signaled???.
+ * The only solution I can imagine is to test each object starting
+ * with the returned index individually - how dull.
+ */
+ any = 0;
+ for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) {
+ if (WaitForSingleObject ( waitbuf[i], NULL ) == WAIT_OBJECT_0) {
+ assert (waitidx[i] >=0 && waitidx[i] < nfds);
+ fds[waitidx[i]].signaled = 1;
+ any = 1;
+ count++;
+ }
+ }
+ if (!any) {
+ DEBUG0 ("Oops: No signaled objects found after WFMO");
+ count = -1;
+ }
+ }
+ else if ( code == WAIT_TIMEOUT ) {
+ DEBUG0 ("WFMO timed out\n" );
+ }
+ else if (code == WAIT_FAILED ) {
+ int le = (int)GetLastError ();
+ if ( le == ERROR_INVALID_HANDLE ) {
+ int k, j = handle_to_fd (waitbuf[i]);
+
+ DEBUG1 ("WFMO invalid handle %d removed\n", j);
+ for (k=0 ; k < nfds; i++ ) {
+ if ( fds[k].fd == j ) {
+ fds[k].for_read = fds[k].for_write = 0;
+ goto restart;
+ }
+ }
+ DEBUG0 (" oops, or not???\n");
+ }
+ DEBUG1 ("WFMO failed: %d\n", le );
+ count = -1;
+ }
+ else {
+ DEBUG1 ("WFMO returned %d\n", code );
+ count = -1;
+ }
+
+ if ( count ) {
+ DEBUG_BEGIN (dbg_help, 3, " signaled [ ");
+ for ( i=0; i < nfds; i++ ) {
+ if ( fds[i].fd == -1 )
+ continue;
+ if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) {
+ DEBUG_ADD2 (dbg_help, "%c%d ",
+ fds[i].for_read? 'r':'w',fds[i].fd );
+ }
+ }
+ DEBUG_END (dbg_help, "]");
+ }
+
+ return count;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/w32-sema.c b/branches/gpgme-1-0-branch/gpgme/w32-sema.c
new file mode 100644
index 00000000..f5337bda
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/w32-sema.c
@@ -0,0 +1,113 @@
+/* w32-sema.c
+ Copyright (C) 2001 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>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <windows.h>
+#include <io.h>
+
+#include "util.h"
+#include "sema.h"
+
+static void
+sema_fatal (const char *text)
+{
+ fprintf (stderr, "sema.c: %s\n", text);
+ abort ();
+}
+
+
+static void
+critsect_init (struct critsect_s *s)
+{
+ CRITICAL_SECTION *mp;
+ static CRITICAL_SECTION init_lock;
+ static int initialized;
+
+ if (!initialized) {
+ /* The very first time we call this function, we assume that
+ only one thread is running, so that we can bootstrap the
+ semaphore code. */
+ InitializeCriticalSection (&init_lock);
+ initialized = 1;
+ }
+ if (!s)
+ return; /* we just want to initialize ourself */
+
+ /* first test whether it is really not initialized */
+ EnterCriticalSection (&init_lock);
+ if ( s->private ) {
+ LeaveCriticalSection (&init_lock);
+ return;
+ }
+ /* now init it */
+ mp = malloc ( sizeof *mp );
+ if (!mp) {
+ LeaveCriticalSection (&init_lock);
+ sema_fatal ("out of core while creating critical section lock");
+ }
+ InitializeCriticalSection (mp);
+ s->private = mp;
+ LeaveCriticalSection (&init_lock);
+}
+
+void
+_gpgme_sema_subsystem_init ()
+{
+ /* fixme: we should check that there is only one thread running */
+ critsect_init (NULL);
+}
+
+
+void
+_gpgme_sema_cs_enter ( struct critsect_s *s )
+{
+ if (!s->private)
+ critsect_init (s);
+ EnterCriticalSection ( (CRITICAL_SECTION*)s->private );
+}
+
+void
+_gpgme_sema_cs_leave (struct critsect_s *s)
+{
+ if (!s->private)
+ critsect_init (s);
+ LeaveCriticalSection ((CRITICAL_SECTION*)s->private);
+}
+
+void
+_gpgme_sema_cs_destroy ( struct critsect_s *s )
+{
+ if (s && s->private) {
+ DeleteCriticalSection ((CRITICAL_SECTION*)s->private);
+ free (s->private);
+ s->private = NULL;
+ }
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/w32-util.c b/branches/gpgme-1-0-branch/gpgme/w32-util.c
new file mode 100644
index 00000000..f01555da
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/w32-util.c
@@ -0,0 +1,144 @@
+/* w32-util.c - Utility functions for the W32 API
+ Copyright (C) 1999 Free Software Foundation, Inc
+ Copyright (C) 2001 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <windows.h>
+#include <io.h>
+
+#include "util.h"
+#include "sema.h"
+
+DEFINE_STATIC_LOCK (get_path_lock);
+
+/* Return a string from the Win32 Registry or NULL in case of error.
+ Caller must release the return value. A NULL for root is an alias
+ for HKEY_CURRENT_USER. */
+static char *
+read_w32_registry_string (const char *root, const char *dir, const char *name)
+{
+ HKEY root_key, key_handle;
+ DWORD n1, nbytes;
+ char *result = NULL;
+
+ if (!root)
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp (root, "HKEY_CLASSES_ROOT"))
+ root_key = HKEY_CLASSES_ROOT;
+ else if (!strcmp (root, "HKEY_CURRENT_USER"))
+ root_key = HKEY_CURRENT_USER;
+ else if (!strcmp (root, "HKEY_LOCAL_MACHINE"))
+ root_key = HKEY_LOCAL_MACHINE;
+ else if (!strcmp (root, "HKEY_USERS"))
+ root_key = HKEY_USERS;
+ else if (!strcmp (root, "HKEY_PERFORMANCE_DATA"))
+ root_key = HKEY_PERFORMANCE_DATA;
+ else if (!strcmp (root, "HKEY_CURRENT_CONFIG"))
+ root_key = HKEY_CURRENT_CONFIG;
+ else
+ return NULL;
+
+ if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle))
+ return NULL; /* No need for a RegClose, so return directly. */
+
+ nbytes = 1;
+ if (RegQueryValueEx (key_handle, name, 0, NULL, NULL, &nbytes))
+ goto leave;
+ n1 = nbytes + 1;
+ result = malloc (n1);
+ if (!result)
+ goto leave;
+ if (RegQueryValueEx (key_handle, name, 0, NULL, result, &n1))
+ {
+ free (result);
+ result = NULL;
+ goto leave;
+ }
+ result[nbytes] = 0; /* Make sure it is really a string. */
+
+ leave:
+ RegCloseKey (key_handle);
+ return result;
+}
+
+
+static const char *
+find_program_in_registry (const char *name)
+{
+ char *program = NULL;
+
+ program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name);
+ if (program)
+ {
+ int i;
+
+ DEBUG2 ("found %s in registry: `%s'", name, program);
+ for (i = 0; program[i]; i++)
+ {
+ if (program[i] == '/')
+ program[i] = '\\';
+ }
+ }
+ return program;
+}
+
+
+const char *
+_gpgme_get_gpg_path (void)
+{
+ static char *gpg_program;
+
+ LOCK (get_path_lock);
+ if (!gpg_program)
+ gpg_program = find_program_in_registry ("gpgProgram");
+#ifdef GPG_PATH
+ if (!gpg_program)
+ gpg_program = GPG_PATH;
+#endif
+ UNLOCK (get_path_lock);
+ return gpg_program;
+}
+
+const char *
+_gpgme_get_gpgsm_path (void)
+{
+ static char *gpgsm_program;
+
+ LOCK (get_path_lock);
+ if (!gpgsm_program)
+ gpgsm_program = find_program_in_registry ("gpgsmProgram");
+#ifdef GPGSM_PATH
+ if (!gpgsm_program)
+ gpgsm_program = GPGSM_PATH;
+#endif
+ UNLOCK (get_path_lock);
+ return gpgsm_program;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/wait-global.c b/branches/gpgme-1-0-branch/gpgme/wait-global.c
new file mode 100644
index 00000000..e6422510
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/wait-global.c
@@ -0,0 +1,357 @@
+/* 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 <errno.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;
+
+ gpgme_ctx_t ctx;
+ /* The status is set when the ctx is moved to the done list. */
+ gpgme_error_t 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 gpgme_error_t
+ctx_active (gpgme_ctx_t ctx)
+{
+ struct ctx_list_item *li = malloc (sizeof (struct ctx_list_item));
+ if (!li)
+ return gpg_error_from_errno (errno);
+ 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 (gpgme_ctx_t ctx, gpgme_error_t 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 gpgme_ctx_t
+ctx_wait (gpgme_ctx_t ctx, gpgme_error_t *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, gpgme_event_io_t type,
+ void *type_data)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) data;
+
+ assert (ctx);
+
+ switch (type)
+ {
+ case GPGME_EVENT_START:
+ {
+ gpgme_error_t err = ctx_active (ctx);
+
+ if (err)
+ {
+ /* An error occured. Close all fds in this context, and
+ send the error in a done event. */
+ unsigned 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:
+ {
+ gpgme_error_t *errp = (gpgme_error_t *) 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. */
+gpgme_ctx_t
+gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang)
+{
+ do
+ {
+ unsigned 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)
+ {
+ int saved_errno = errno;
+ UNLOCK (ctx_list_lock);
+ if (status)
+ *status = gpg_error_from_errno (saved_errno);
+ 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)
+ {
+ int saved_errno = errno;
+ free (fdt.fds);
+ if (status)
+ *status = gpg_error_from_errno (saved_errno);
+ return NULL;
+ }
+
+ for (i = 0; i < fdt.size && nr; i++)
+ {
+ if (fdt.fds[i].fd != -1 && fdt.fds[i].signaled)
+ {
+ gpgme_ctx_t ictx;
+ gpgme_error_t 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)
+ {
+ /* An error occured. Close all fds in this context,
+ and signal it. */
+ unsigned 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)
+ {
+ gpgme_error_t err = 0;
+ _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
+ }
+ }
+ UNLOCK (ctx_list_lock);
+
+ {
+ gpgme_ctx_t dctx = ctx_wait (ctx, status);
+
+ if (dctx)
+ {
+ ctx = dctx;
+ hang = 0;
+ }
+ }
+ }
+ while (hang);
+
+ return ctx;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/wait-private.c b/branches/gpgme-1-0-branch/gpgme/wait-private.c
new file mode 100644
index 00000000..c9c5ce55
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/wait-private.c
@@ -0,0 +1,150 @@
+/* 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 <errno.h>
+
+#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, gpgme_event_io_t type,
+ void *type_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:
+ 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. */
+gpgme_error_t
+_gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)
+{
+ gpgme_error_t err = 0;
+ int hang = 1;
+
+ do
+ {
+ int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
+ unsigned int i;
+
+ if (nr < 0)
+ {
+ /* An error occured. Close all fds in this context, and
+ signal it. */
+ unsigned int idx;
+
+ err = gpg_error_from_errno (errno);
+ 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)
+ {
+ /* An error occured. Close all fds in this context,
+ and signal it. */
+ unsigned 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. */
+gpgme_error_t
+_gpgme_wait_one (gpgme_ctx_t ctx)
+{
+ return _gpgme_wait_on_condition (ctx, NULL);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/wait-user.c b/branches/gpgme-1-0-branch/gpgme/wait-user.c
new file mode 100644
index 00000000..1fbe9cb2
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/wait-user.c
@@ -0,0 +1,124 @@
+/* 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"
+
+
+/* The user event loops are used for all asynchronous operations for
+ which a user callback is defined. */
+
+
+/* Internal I/O Callbacks. */
+
+gpgme_error_t
+_gpgme_user_io_cb_handler (void *data, int fd)
+{
+ gpgme_error_t err;
+ struct tag *tag = (struct tag *) data;
+ gpgme_ctx_t 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)
+ {
+ unsigned 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);
+ }
+ else
+ {
+ unsigned int i;
+
+ 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);
+ }
+ 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. */
+gpgme_error_t
+_gpgme_wait_user_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc,
+ void *fnc_data, void **r_tag)
+{
+ gpgme_ctx_t ctx = (gpgme_ctx_t) data;
+ struct tag *tag;
+ gpgme_error_t 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;
+ gpgme_ctx_t ctx;
+
+ assert (tag);
+ ctx = tag->ctx;
+
+ (*ctx->io_cbs.remove) (tag->user_tag);
+ _gpgme_remove_io_cb (data);
+}
+
+
+void
+_gpgme_wait_user_event_cb (void *data, gpgme_event_io_t type, void *type_data)
+{
+ gpgme_ctx_t ctx = data;
+
+ if (ctx->io_cbs.event)
+ (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data);
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/wait.c b/branches/gpgme-1-0-branch/gpgme/wait.c
new file mode 100644
index 00000000..b874c570
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/wait.c
@@ -0,0 +1,168 @@
+/* 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "util.h"
+#include "context.h"
+#include "ops.h"
+#include "wait.h"
+#include "sema.h"
+#include "io.h"
+#include "engine.h"
+#include "debug.h"
+
+
+void
+_gpgme_fd_table_init (fd_table_t fdt)
+{
+ fdt->fds = NULL;
+ fdt->size = 0;
+}
+
+void
+_gpgme_fd_table_deinit (fd_table_t fdt)
+{
+ if (fdt->fds)
+ free (fdt->fds);
+}
+
+
+/* XXX We should keep a marker and roll over for speed. */
+static gpgme_error_t
+fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx)
+{
+ unsigned int i, j;
+ struct io_select_fd_s *new_fds;
+
+ for (i = 0; i < fdt->size; i++)
+ {
+ if (fdt->fds[i].fd == -1)
+ break;
+ }
+ if (i == fdt->size)
+ {
+#define FDT_ALLOCSIZE 10
+ new_fds = realloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE)
+ * sizeof (*new_fds));
+ if (!new_fds)
+ return gpg_error_from_errno (errno);
+
+ fdt->fds = new_fds;
+ fdt->size += FDT_ALLOCSIZE;
+ for (j = 0; j < FDT_ALLOCSIZE; j++)
+ fdt->fds[i + j].fd = -1;
+ }
+
+ fdt->fds[i].fd = fd;
+ fdt->fds[i].for_read = (dir == 1);
+ fdt->fds[i].for_write = (dir == 0);
+ fdt->fds[i].frozen = 0;
+ fdt->fds[i].signaled = 0;
+ fdt->fds[i].opaque = opaque;
+ *idx = i;
+ 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. */
+gpgme_error_t
+_gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc,
+ void *fnc_data, void **r_tag)
+{
+ gpgme_error_t err;
+ gpgme_ctx_t ctx = (gpgme_ctx_t) data;
+ fd_table_t fdt;
+ struct wait_item_s *item;
+ struct tag *tag;
+
+ assert (fnc);
+ assert (ctx);
+
+ fdt = &ctx->fdt;
+ assert (fdt);
+
+ tag = malloc (sizeof *tag);
+ if (!tag)
+ return gpg_error_from_errno (errno);
+ tag->ctx = ctx;
+
+ /* Allocate a structure to hold information about the handler. */
+ item = calloc (1, sizeof *item);
+ if (!item)
+ {
+ int saved_errno = errno;
+ free (tag);
+ return gpg_error_from_errno (saved_errno);
+ }
+ item->ctx = ctx;
+ item->dir = dir;
+ item->handler = fnc;
+ item->handler_value = fnc_data;
+
+ err = fd_table_put (fdt, fd, dir, item, &tag->idx);
+ if (err)
+ {
+ free (tag);
+ free (item);
+ return err;
+ }
+
+ *r_tag = tag;
+ return 0;
+}
+
+
+void
+_gpgme_remove_io_cb (void *data)
+{
+ struct tag *tag = data;
+ gpgme_ctx_t ctx;
+ fd_table_t fdt;
+ int idx;
+
+ assert (tag);
+ ctx = tag->ctx;
+ assert (ctx);
+ fdt = &ctx->fdt;
+ assert (fdt);
+ idx = tag->idx;
+
+ DEBUG2 ("setting fd %d (item=%p) done", fdt->fds[idx].fd,
+ fdt->fds[idx].opaque);
+ free (fdt->fds[idx].opaque);
+ free (tag);
+
+ /* Free the table entry. */
+ fdt->fds[idx].fd = -1;
+ fdt->fds[idx].for_read = 0;
+ fdt->fds[idx].for_write = 0;
+ fdt->fds[idx].opaque = NULL;
+}
diff --git a/branches/gpgme-1-0-branch/gpgme/wait.h b/branches/gpgme-1-0-branch/gpgme/wait.h
new file mode 100644
index 00000000..9cc17226
--- /dev/null
+++ b/branches/gpgme-1-0-branch/gpgme/wait.h
@@ -0,0 +1,79 @@
+/* wait.h - Definitions for the wait queue interface.
+ 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
+
+#include "gpgme.h"
+#include "sema.h"
+
+struct fd_table
+{
+ 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
+{
+ gpgme_ctx_t ctx;
+ gpgme_io_cb_t 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. */
+ gpgme_ctx_t 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);
+
+gpgme_error_t _gpgme_add_io_cb (void *data, int fd, int dir,
+ gpgme_io_cb_t fnc, void *fnc_data, void **r_tag);
+void _gpgme_remove_io_cb (void *tag);
+void _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data);
+void _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data);
+
+gpgme_error_t _gpgme_wait_user_add_io_cb (void *data, int fd, int dir,
+ gpgme_io_cb_t fnc, void *fnc_data,
+ void **r_tag);
+void _gpgme_wait_user_remove_io_cb (void *tag);
+void _gpgme_wait_user_event_cb (void *data, gpgme_event_io_t type,
+ void *type_data);
+
+gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx);
+
+#endif /* WAIT_H */