diff options
Diffstat (limited to 'src')
95 files changed, 47745 insertions, 0 deletions
diff --git a/src/ChangeLog-2011 b/src/ChangeLog-2011 new file mode 100644 index 0000000..c1a901a --- /dev/null +++ b/src/ChangeLog-2011 @@ -0,0 +1,7148 @@ +2011-12-02 Werner Koch <wk@g10code.com> + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2011-10-25 Marcus Brinkmann <marcus@g10code.com> + + * Makefile.am: Remove build rules for libgpgme-pth. + * gpgme.m4: Remove support for libgpgme-pth. + +2011-05-26 Marcus Brinkmann <marcus@g10code.com> + + * decrypt.c (gpgme_op_decrypt_start, gpgme_op_decrypt): Check CTX. + * decrypt-verify.c (gpgme_op_decrypt_verify_start) + (gpgme_op_decrypt_verify): Likewise. + * delete.c (gpgme_op_delete_start, gpgme_op_delete): Likewise. + * edit.c (gpgme_op_edit_start, gpgme_op_edit) + (gpgme_op_card_edit_start, gpgme_op_card_edit): Likewise. + * encrypt.c (gpgme_op_encrypt_start, gpgme_op_encrypt): Likewise. + * encrypt-sign.c (gpgme_op_encrypt_sign_start) + (gpgme_op_encrypt_sign): Likewise. + * export.c (gpgme_op_export_start, gpgme_op_export) + (gpgme_op_export_ext_start, gpgme_op_export_ext) + (gpgme_op_export_keys_start, gpgme_op_export_keys): Likewise. + * genkey.c (gpgme_op_genkey_start, gpgme_op_genkey): Likewise. + * getauditlog.c (gpgme_op_getauditlog_start) + (gpgme_op_getauditlog): Likewise. + * gpgconf.c (gpgme_op_conf_load, gpgme_op_conf_save): Likewise. + * import.c (gpgme_op_import_start, gpgme_op_import_keys_start) + (gpgme_op_import_keys, gpgme_op_import): Likewise. + * keylist.c (gpgme_op_keylist_start, gpgme_op_keylist_ext_start): + Likewise. + * opassuan.c (gpgme_op_assuan_transact_start) + (gpgme_op_assuan_transact_ext): Likewise. + * passwd.c (gpgme_op_passwd_start, gpgme_op_passwd): Likewise. + * sign.c (gpgme_op_sign_start, gpgme_op_sign): Likewise. + * trustlist.c (gpgme_op_trustlist_start) + (gpgme_op_trustlist_next): Likewise. + * verify.c (gpgme_op_verify_start, gpgme_get_sig_key): Likewise. + * op-support.c (_gpgme_op_data_lookup): Likewise. + * vfs-create.c (gpgme_op_vfs_transact, gpgme_op_vfs_create): Likewise. + * vfs-mount.c (gpgme_op_vfs_mount, gpgme_op_vfs_transact): Likewise. + * gpgme.c (gpgme_set_protocol) + (gpgme_set_sub_protocol) + (gpgme_set_armor, gpgme_set_include_certs) + (gpgme_set_keylist_mode, gpgme_set_passphrase_cb) + (gpgme_set_progress_cb, gpgme_set_io_cbs, gpgme_set_locale) + (gpgme_ctx_set_engine_info, gpgme_sig_notation_clear): Likewise. + * gpgme.c (gpgme_new): Check for valid R_CTX. + (gpgme_cancel, gpgme_cancel_async, gpgme_release): Likewise. + +2011-04-06 Werner Koch <wk@g10code.com> + + * gpgme-config.in: Add option --host. Change options --cflags and + --libs to collapse duplicate include and lib dirs. Try to put + extra libs at the end. + + * gpgme.h.in: Use INSERT__TYPEDEFS_FOR_GPGME_H to include platform + specific typedefs. + +2011-02-03 Werner Koch <wk@g10code.com> + + * extra-stati.h: New. + * mkstatus: Extend to also process extra-stati.h + * Makefile.am (main_sources): Add extra-stati.h + (status-table.h): Depend on extra-stati.h and adjust rule. + +2011-02-03 Marcus Brinkmann <marcus@g10code.com> + + * w32-io.c (_gpgme_io_socket): Return fd, not res. + +2011-02-02 Marcus Brinkmann <mb@g10code.com> + + * assuan-support.c (my_socket, my_connect): New functions. + (_gpgme_assuan_system_hooks): Add my_Socket, my_connect. + * priv-io.h (_gpgme_io_socket): New prototype. + * w32-io.c (pid_to_handle, handle_to_oid, fd_to_handle): Remove macros. + (is_socket): Remove function. + (_gpgme_io_spawn) [HAVE_W32CE_SYSTEM]: Remove some dead code. + (_gpgme_io_spawn): Translate handles before DuplicateHandle them. + +2011-02-02 Marcus Brinkmann <mb@g10code.com> + + * w32-util.c (mkstemp): Don't use CreateFile instead of open (the + function is not used on Windows CE, and the callers were not + adjusted). + +2011-01-21 Marcus Brinkmann <mb@g10code.com> + + * engine-gpgconf.c (_gpgme_conf_opt_change): Fix the case that is + not self-assignment. + +2010-12-08 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (strcpy_escaped_plus): New. + (DIM, xtoi_1, xtoi_2): New. + (cmd_keylist): Allow for multiple patterns. + +2010-11-23 Marcus Brinkmann <mb@g10code.com> + + * w32-io.c (create_reader, create_writer): Use small stack size on + Windows CE. + +2010-11-23 Marcus Brinkmann <mb@g10code.com> + + * gpgme.h.in (gpgme_conf_arg_new): Make VALUE arg const void *. + * gpgconf.c (_gpgme_conf_arg_new): Likewise. + (gpgme_conf_arg_new): Likewise. + * engine-gpgconf.c (_gpgme_conf_arg_new): Likewise. + (gpgconf_write): Remove debug hack. + +2010-11-19 Marcus Brinkmann <mb@g10code.com> + + * engine-gpgconf.c (_gpgme_conf_opt_change): Support + self-assignment. Requested by Marc Mutz. + +2010-11-17 Marcus Brinkmann <mb@g10code.com> + + * vasprintf.c (int_vasprintf) [HAVE_W32CE_SYSTEM]: Just use a + fixed size buffer, as va_copy is not easy to fake. + +2010-11-15 Marcus Brinkmann <mb@g10code.com> + + * w32-ce.h (strcasecmp, strdup) [_MSC_VER]: Define. + * genkey.c, passphrase.c: Include util.h. + + * w32-util.c (_gpgme_w32ce_get_debug_envvar): Fix return value. + +2010-11-15 Werner Koch <wk@g10code.com> + + * data-compat.c (gpgme_data_new_from_filepart) + (gpgme_data_new_from_file) [W32CE && _MSC_VER]: Return not + GPG_ERR_NOT_IMPLEMENTED. + + * w32-ce.h (HKEY_PERFORMANCE_DATA, HKEY_CURRENT_CONFIG, _IOLBF) + (abort) [_MSC_VER]: Provide these macros. + + * ath.h [W32CE && _MSC_VER]: Include winsock2.h. + + * ath.c (ath_read, ath_write) [W32CE && _MSC_VER]: Do not call + non-available functions. + +2010-11-04 Werner Koch <wk@g10code.com> + + * w32-ce.h [_MSC_VER && W32CE]: Undef leave. + * export.c: Include util.h so that we get the above undef. + + * memrchr.c: Remove. Used to be a replacement function required + by the formerly included assuan code. + +2010-11-03 Werner Koch <wk@g10code.com> + + * debug.c (_gpgme_debug) [W32CE]: Replace locatime by GetLocalTime. + + * signers.c (gpgme_signers_clear): Remove useless return. + Reported by Patrick Spendrin. + + * w32-util.c: s/__inline__/GPG_ERR_INLINE/ + + * setenv.c: Include string.h due to our strerror replacement. + + * w32-ce.h (access, bsearch): New macros. + * w32-ce.c (_gpgme_wince_access): New. + (RegQueryValueExA): Change DATA to a void*. + (_gpgme_wince_bsearch): New. Taken from glibc 2.6. + + Guard include of sys/stat.h and sys/types.h. + +2010-11-02 Werner Koch <wk@g10code.com> + + * data-fd.c (read, write, lseek) [W32CE && ! __MINGW32CE__]: New. + Taken from Pedro Alves Public Domain code. + + * w32-ce.h (SHGetSpecialFolderPath): Remove our defines and + prototypes. We use the system provided prototypes now. + * w32-ce.c: Include shlobj.h + (_WIN32_IE): Define to 0x0400 + (CreateFileA): New. + * w32-util.c: Explicitly include windows headers before util.h. + (_gpgme_w32ce_get_debug_envvar): Do not use wchar_t strings for + read_w32_registry_string. + (mkstemp): Use CreateFile instead of open. + + * w32-io.c (handle_to_fd, fd_tohandle): Add. We need them for W32. + * w32-util.c (_WIN32_IE): Define to 0x0400. + + * util.h [W32]: Include windows.h. + * w32-sema.c: Do not include windows.h directly. + * ath.c (ssize_t, pid_t)[_MSC_VER]: Add new types. + * gpgme.c (gpgme_result_ref, gpgme_result_unref): Do not use a + void pointer in pointer arithmetic. + * w32-util.c: Include util.h prior to ath.h. Don't include + windows.h directly. + (F_OK): Define if not defined. + * w32-ce.c: Include string.h. + (RegQueryValueExA): Use WINAPI modifier to match the declaration. + * vfs-create.c: Include string.h because under W32CE with MSC we + get a warning related to our strerror replacement. + * encrypt-sign.c: Include stdlib.h, string.h and errno.h. + * priv-io.h [W32CE]: Include w32-ce.h + * w32-ce.h: Include winsock2.h and ws2tcpip.h. + (_MSV_VER): Remove useless macro. + (pid_t): Add typedef. + + Guard all includes of unistd.h and sys/time.h. + +2010-10-28 Marcus Brinkmann <marcus@g10code.com> + + * opassuan.c (gpgme_op_assuan_transact_ext): Fix uninitialized + value use. Reported by Marc Mutz. + +2010-10-07 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (ARGP_ERR_UNKNOWN): Use EDEADLK if available. + + * w32-util.c (_gpgme_w32ce_get_debug_envvar) [W32CE]: New. + * debug.c (debug_init) [W32CE]: Use new function. + +2010-09-16 Werner Koch <wk@g10code.com> + + * import.c: Include "util.h". + (parse_import): Return GPG_ERR_MISSING_ISSUER_CERT. + + * util.h: Add fallback define for GPG_ERR_MISSING_ISSUER_CERT. + * op-support.c: Include "util.h". + (_gpgme_parse_inv_recp): Handle new code 12. + +2010-09-02 Marcus Brinkmann <marcus@g10code.de> + + * error.c (gpgme_err_code_to_errno): Fix cut and paste bug (thanks + to Marc Mutz). + +2010-09-01 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c: Revert change from 2009-06-18, as it created a race + condition. + +2010-08-18 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.def: Add gpgme_err_code_from_syserror and gpgme_err_set_errno. + * libgpgme.vers: Likewise. + * gpgme.h.in (gpgme_error_from_errno): Fix return type to + gpgme_error_t. + (gpgme_err_code_from_syserror, gpgme_err_set_errno): New prototype. + (gpgme_error_from_syserror): New inline function (why are + gpgme_err_make_from_errno and gpgme_error_from_errno not inline + functions?). + * error.c (gpgme_error_from_errno): Fix return type to gpgme_error_t. + (gpgme_err_set_errno, gpgme_err_code_from_syserror): New functions. + +2010-08-03 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-tool.c (result_encrypt_to_xml, result_sign_to_xml) + (result_verify_to_xml, result_import_to_xml) + (result_genkey_to_xml): Check vigorously for null pointers. + + * w32-io.c (GPGCEDEV_IOCTL_ASSIGN_RVID): New macro. + (_gpgme_io_spawn): Use ASSIGN_RVID. + +2010-06-11 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (_gpgme_io_spawn): Remove debug printf. + +2010-06-10 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-tool.c (gpgme_server): Use special hack for Windows CE to + get at stdin and stdout. + + * engine-gpgsm.c (gpgsm_new): Translate returned achild_fds back + to child_fds. + + * debug.h (TRACE_SUC6): New macro. + * w32-io.c (MAX_SLAFD): New macro. + (fd_table): New static variable. + (new_fd, release_fd): New functions. + (fd_to_handle, handle_to_fd, handle_to_socket): Remove macros. + (MAX_READERS, MAX_WRITERS): Increase to 64. + (notify_table): Increase to MAX_SLAFD. + (struct reader_context_s, struct writer_context_s): Add member + file_sock. + (reader, writer): Use file_hd vs file_sock to decide if socket + operations to use. Remove auto-detect mode. + (create_reader, create_writer): Set file_sock. Unblock pending + thread only if this is a pipe fd. + (_gpgme_io_pipe): Allocate fds from table and return slot indices + instead of windows handles. This allows to properly handle RVIDs. + (_gpgme_io_close): Handle dup'ed file descriptors. + (build_commandline) [HAVE_W32_SYSTEM]: Use RVID from fd table now. + (_gpgme_io_spawn): Use fd table now. + (_gpgme_io_fd2str): Use RVID from fd table now. + (_gpgme_io_dup): Implement using fd table. + (_gpgme_io_socket): Allocate fds from table. + (_gpgme_io_connect): Use fd from table. + + * w32-glib-io.c (find_channel): Check that the slot is used. + +2010-06-09 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c [HAVE_W32CE_SYSTEM]: Include assuan.h and winioctl.h. + (GPGCEDEV_IOCTL_UNBLOCK) [HAVE_W32CE_SYSTEM]: Define. + (set_synchronize) [HAVE_W32CE_SYSTEM]: Stub it out. + (is_socket): Allow to return -1 for auto-detect (old behaviour). + (is_socket) [HAVE_W32CE_SYSTEM]: Return -1. + (reader): Handle auto-detect case. Handle ctx->stop_me before + checking for EOF. + (destroy_reader) [HAVE_W32CE_SYSTEM]: Unblock a pending reader. + (writer): Handle auto-detect case. Handle ctx->stop_me with + ERROR_BUSY. + (destroy_writer) [HAVE_W32CE_SYSTEM]: Unblock a pending writer. + (_gpgme_io_pipe) [HAVE_W32CE_SYSTEM]: Implement in terms of a + half-pipe. + (build_commandline) [HAVE_W32CE_SYSTEM]: New function. + (_gpgme_io_spawn) [HAVE_W32CE_SYSTEM]: Implement it differently + for this platform. + (_gpgme_io_fd2str) [HAVE_W32CE_SYSTEM]: Implement it for RVIDs. + (_gpgme_io_dup) [HAVE_W32CE_SYSTEM]: Stub it out. + + * gpgme-tool.c (result_add_timestamp): Add missing NULL argument. + (result_sign_to_xml): Protect against NULL fingerprint. + (struct server): New members input_fd, input_filename, + input_stream output_fd, output_filename, output_stream, + message_filename, message_stream. + (server_reset_fds): Deallocate those. + (server_parse_fd): New function. + (server_data_obj): Take optional filename argument and direction + argument. Also take new argument to return a filestream that + needs to be closed after destroying the data object. + Change all callers, too. + (input_notify, output_notify): Removed. + (cmd_input, cmd_output): New functions. + (gpgme_server): Do not register input and output notifier. + (register_commands): Use cmd_input and cmd_output. + (cmd_message): Rewritten to use server_parse_fd. + (cmd_delete, cmd_keylist): Fix inverted option check. + (main) [HAVE_W32CE_SYSTEM]: Sleep a bit to work around bug in ssh. + + * genkey.c (gpgme_op_genkey): Return err with TRACE_ERR. + +2010-05-12 Marcus Brinkmann <marcus@g10code.de> + + * conversion.c (_gpgme_timegm) [HAVE_W32_SYSTEM]: New static + function. + (_gpgme_parse_timestamp) [HAVE_W32_SYSTEM]: Use it. + + * gpgme-tool.c (main): Protect call to setlocale with + HAVE_SETLOCALE. + + * Makefile.am (system_components): Remove custom cppflags from + RCCOMPILE (because gpg-error adds -idirafter that makes RC bail. + [HAVE_W32CE_SYSTEM]: Add w32-ce.h and w32-ce.c, clear + libexec_PROGRAMS. + * w32-ce.h, w32-ce.c: New files. + + * priv-io.h: Include <sys/types.h> + * util.h: Likewise. + +2010-05-11 Marcus Brinkmann <marcus@g10code.de> + + * w32-util.c: Include ath.h + (HAVE_ALLOW_SET_FOREGROUND_WINDOW) [!HAVE_W32CE_SYSTEM]: Define + it. + (RTLD_LAZY, dlopen, dlsym, + dlclose) [!HAVE_ALLOW_SET_FORGROUND_WINDOW]: Don't define anymore. + (_gpgme_allow_set_foreground_window) [!HAVE_ALLOW_SET_FOREGROUND_WINDOW]: + Make it a stub. + (read_w32_registry_string): Use FooA variants of Windows functions + instead of Foo (which dispatches depending on UNICODE). + [!HAVE_W32CE_SYSTEM]: Don't check environment. + (w32_shgetfolderpath): Remove. + (find_program_at_standard_place): Call + SHGetSpecialFolderPath (which is available on all Windows systems + and also Windows CE). + (mkstemp): Use ath_self instead of getpid. + (_gpgme_mkstemp): Use GetTempPathA instead of GetTempPath. + + * gpgme.h.in: Use _WIN32 instead of _MSC_VER. Include time.h for + time_t. + +2010-05-07 Marcus Brinkmann <marcus@g10code.de> + + * engine-g13.c, gpgme.c, engine-gpgsm.c, engine-gpg.c, + op-support.c, engine-assuan.c, gpgme-tool.c: Include <locale.h> + only if available with HAVE_LOCALE_H and conditionalize use of + LC_CTYPE on its definition. + * engine-gpgconf.c: Do not include <locale.h>. + + * engine-gpgsm.c (gpgsm_new, start): Cast between int and + assuan_fd_t. + * assuan-support.c (my_pipe, my_close, my_read, my_write): Likewise. + * gpgme-tool.c (server_data_obj, server_reset_fds, gpgme_server), + (my_recvmsg, my_sendmsg, my_spawn): Likewise. + * engine-assuan.c (start): Likewise. + * engine-g13.c (start): Likewise. + +2010-05-06 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c, w32-io.c, w32-qt-io.cpp, w32-sema.c, w32-util.c: + Do not include <signal.h>. + + * sign.c, data-user.c, conversion.c, debug.c, verify.c, data.c, + decrypt.c, delete.c, assuan-support.c, import.c, engine-gpgsm.c, + data-mem.c, op-support.c, w32-io.c, w32-util.c, data-compat.c: Use + gpg_error_from_syserror instead gpg_error_from_errno, and use + gpg_err_set_errno to set error number. + * setenv.c: Include <gpg-error.h> and define __set_errno to use + gpg_err_set_errno. + * gpgme-tool.c (ARGP_ERR_UNKNOWN): Define to EDEADLOCK (which is + mapped in Windows CE) instead of E2BIG (which is not). + (gt_import_keys): Initialize err. + +2010-04-19 Marcus Brinkmann <marcus@g10code.de> + + * assuan-support.c (my_spawn): Cast to avoid warning. + * engine-g13.c (g13_new): Make ARGV array of pointer to const + char. + (g13_assuan_simple_command) [!USE_DESCRIPTOR_FUNCTION]: Don't define. + * ops.h (_gpgme_key_append_name): Same in prototype. + * key.c (_gpgme_key_append_name): Make SRC argument pointer to + const char. + * posix-util.c (_gpgme_get_uiserver_socket_path): Make HOMEDIR + const. + * vfs-mount.c (gpgme_op_vfs_transact_start): Never define this + potentially useful but currently unused function. + * vfs-create.c (gpgme_op_vfs_transact_start): Likewise. + +2010-04-16 Werner Koch <wk@g10code.com> + + * w32-io.c (is_socket): New. + (reader, writer): Use it to figure out the API to use. + +2010-03-15 Werner Koch <wk@g10code.com> + + * gpgme.h.in: Add autoconf template to set generated file to + read-only in an emacs buffer. + +2010-03-12 Werner Koch <wk@g10code.com> + + * gpgme.h.in (GPGME_STATUS_SUCCESS): Use the right file for the + change; see below. + + * passwd.c (op_data_t): New. + (passwd_start): Setup OPD. + (passwd_status_handler): Return GPG_ERR_NOT_SUPPORTED if needed. + * context.h (OPDATA_PASSWD): New. + * gpgme.h (GPGME_STATUS_SUCCESS): New. + +2010-03-09 Werner Koch <wk@g10code.com> + + * engine-gpgsm.c (gpgsm_keylist): Try to start the agent. + +2010-02-17 Werner Koch <wk@g10code.com> + + * posix-io.c (notify_table): Change implementation. + (notify_table_item_t, notify_table_size, notify_table_lock): New. + (_gpgme_io_close, _gpgme_io_set_close_notify): Adjust for new + implementation. + +2010-02-16 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (spacep, has_option, skip_options): New. + (cmd_export): Implement option --minimal. + + * gpgme.h.in (GPGME_EXPORT_MODE_MINIMAL): New. + * export.c (export_start, export_ext_start): Implement it. + * engine-gpg.c (export_common): Ditto. + +2010-01-25 Werner Koch <wk@g10code.com> + + * w32-io.c (_gpgme_io_connect): Fix return code check to make it work. + + * version.c (do_subsystem_inits): Remove superfluous second + WSAStartup. + +2010-01-22 Werner Koch <wk@g10code.com> + + * w32-io.c (writer): Try to use send first. + (reader): Try to use recv first. + +2010-01-08 Werner Koch <wk@g10code.com> + + * engine-gpg.c (gpg_passwd): New. + (_gpgme_engine_ops_gpg): Register. + * passwd.c (parse_error): New. + (passwd_status_handler): Use it. + +2010-01-07 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-tool.c (result_xml_write_cb_t, struct result_xml_state): + New types. + (MAX_TAGS): New macro. + (result_init, result_xml_indent, result_xml_tag_start) + (result_xml_tag_data, result_xml_tag_end, result_add_error) + (result_add_pubkey_algo, result_add_hash_algo, result_add_keyid) + (result_add_fpr, result_add_timestamp, result_add_sig_mode) + (result_add_value, result_add_string, result_encrypt_to_xml) + (result_decrypt_to_xml, result_sign_to_xml) + (result_verify_to_xml, result_import_to_xml) + (result_genkey_to_xml, result_keylist_to_xml) + (result_vfs_mount_to_xml): New functions. + (gt_result): Rewritten. + +2010-01-05 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (gt_passwd, cmd_passwd): New. + (register_commands): Register. + + * gpgme.h.in (gpgme_op_passwd_start, gpgme_op_passwd): New. + * libgpgme.vers, gpgme.def: Add new functions. + * passwd.c: New. + * Makefile.am (main_sources): Add passwd.c + * engine.c, engine.h (_gpgme_engine_op_passwd): New. + * engine-backend.h (struct engine_ops): Add PASSWD. + * engine-gpgsm.c (gpgsm_passwd): New. + (_gpgme_engine_ops_gpgsm): Register. + (gpgsm_reset): Reset only if we have a conenction. + + * gpgme.h.in (GPGME_PK_ECDSA, GPGME_PK_ECDH): New. + * gpgme.c (gpgme_pubkey_algo_name): Add them. + +2009-12-22 Marcus Brinkmann <marcus@g10code.de> + + * debug.c: Test for TLS, not __GNUC__ + +2009-12-15 Marcus Brinkmann <marcus@g10code.de> + + * assuan-support.c (my_spawn): Calloc, not malloc, the fd_items. + +2009-12-10 Werner Koch <wk@g10code.com> + + * debug.c (debug_init): Test on sgid process. + +2009-12-08 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (LTRCCOMPILE): Refactor with ... + (RCCOMPILE): ... this new macro. + (SUFFIXES): Add .lo. + (gpgme_res_ldflag): Removed. + (gpgme_res): Use libtool object file name here. + (libgpgme_la_LDFLAGS): Remove gpgme_res_ldflag usage. + (libgpgme_la_LIBADD): Add gpgme_res. + + * ath.c (ath_self) [HAVE_W32_SYSTEM]: Fix typo. + +2009-12-02 Werner Koch <wk@g10code.com> + + * gpgconf.c (gpgme_conf_arg_release): No return in a function + returning void. Reported by Wyllys Ingersoll. + +2009-12-01 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (cmd_getauditlog): Add flag --html. + (hlp_getauditlog): New. + + * gpgme-tool.c (GT_GCC_A_SENTINEL, GT_GCC_A_PRINTF): New. + (gt_write_status): Use sentinel. + (argp_error, log_error): Use printf attribute. + (argp_parse): Remove extra argument to argp_error. + (_gt_progress_cb, gt_get_engine_info, gt_get_keylist_mode) + (gt_result): Add NULL arg. + +2009-11-26 Marcus Brinkmann <marcus@g10code.de> + + * opassuan.c (opassuan_start): Allocate result structure before + beginning operation. + +2009-11-25 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-tool.c (gpgme_server): Use assuan_fd_t and assuan_fdopen + on fds. + +2009-11-13 <wk@g10code.com> + + * sign.c (_gpgme_sign_status_handler): Handle SIG_CREATED_SEEN. + * engine-uiserver.c (uiserver_sign): Make sending SENDER optional. + +2009-11-10 Marcus Brinkmann <marcus@g10code.de> + + * op-support.c (_gpgme_op_reset): Instead of last change, only set + sub protocol if it is not the default. + +2009-11-10 Werner Koch <wk@g10code.com> + + * op-support.c (_gpgme_op_reset): Ignore GPG_ERR_NOT_IMPLEMENTED + while setting the sub protocol. + + * engine-uiserver.c (uiserver_new): Pass fdpassing flag to + assuan_socket_connect. + (set_recipients): Replace fingerprint by user id. + + * engine-gpgsm.c (set_recipients): Fix non-terminating loop in + case of a missing key. + +2009-11-10 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_new): Set default sub protocol. + * gpgme-tool.c: Implement get sub protocol. + + * gpgme.h.in (gpgme_get_sub_protocol): Add prototype. + * gpgme.def, libgpgme.vers: Add gpgme_get_sub_protocol. + * context.h (struct gpgme_context): New member sub_protocol. + * gpgme.c (gpgme_set_sub_protocol): Set CTX->sub_protocol. + (gpgme_get_sub_protocol): New function. + * op-support.c (_gpgme_op_reset): Set sub protocol. + + * Makefile.am (uiserver_components): New variable. + (main_sources): Add it. + * ops.h, key.c (_gpgme_key_append_name): Take CONVERT argument, + implement it. Adjust callers. + (gpgme_key_from_uid): New function. + * gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_DEFAULT. + (gpgme_encrypt_flags_t): Add GPGME_ENCRYPT_PREPARE, + GPGME_ENCRYPT_EXPECT_SIGN. + (gpgme_set_sub_protocol, gpgme_key_from_uid): New functions. + * libgpgme.vers, gpgme.def: Add new functions. + * gpgme.c (gpgme_set_protocol): Add UIServer protocol. + (gpgme_set_sub_protocol): New function. + (gpgme_get_protocol_name): Add UIServer and default protocol. + * assuan-support.c: Return correct error values, implement + socketpair for POSIX. + * priv-io.h, posix-io.c, w32-io.c, w32-glib-io.c, + w32-qt-io.cpp (_gpgme_io_spawn): Add ATFORK and ATFORKVALUE + arguments. Implement it for POSIX. Adjust all callers. + * engine.h, engine-backend.h (_gpgme_engine_set_protocol) + (_gpgme_engine_op_decrypt_verify): New prototypes. Adjust all + users. + * engine.c (engine_ops, gpgme_get_engine_info): Add UIServer + engine. + (_gpgme_engine_set_protocol, _gpgme_engine_op_decrypt_verify): New + function. + * decrypt-verify.c (decrypt_verify_start): Call + _gpgme_engine_op_decrypt_verify. + * util.h, posix-util.c, + w32-util.c (_gpgme_get_uiserver_socket_path): New function. + * engine-gpgsm.c (gpgsm_set_fd): Fix _gpgme_io_pipe invocation. + * gpgme-tool.c: Some support for UIServer protocol. + * engine-uiserver.c: New file. + +2009-11-09 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_new): Close server side FDs. + +2009-11-06 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-tool.c (struct gpgme_tool): New members write_data and + write_data_hook. + (gt_write_data): New function. + (gt_result): Output vfs_mount result. + (server_write_data): New function. + (gpgme_server): Initialize write_data members. + +2009-11-05 Marcus Brinkmann <marcus@g10code.de> + + * engine-g13.c (struct engine_g13): Remove members RESULT_CB and + RESULT_CB_VALUE. + (g13_assuan_simple_command, status_handler): Don't use those anymore. + (g13_transact): Remove them from argument list, too. + * vfs-mount.c (_gpgme_vfs_mount_status_handler): New function. + (_gpgme_op_vfs_mount): Pass it to transact. + + * engine-assuan.c (llass_new): Update use of assuan_socket_connect. + * engine-gpgsm.c (gpgsm_new): Update use of assuan_pipe_connect. + * engine-g13.c (g13_new): Likewise. + + * priv-io.h (IOSPAWN_FLAG_NOCLOSE): New flag. + * w32-io.c (_gpgme_io_spawn): Implement this flag. + * posix-io.c (_gpgme_io_spawn): Likewise. + * w32-glib-io.c (_gpgme_io_spawn): Likewise. + * assuan-support.c (my_spawn): Set this flag. + + * decrypt.c (gpgme_op_decrypt_start): Fix use of debug macro. + * decrypt-verify.c (gpgme_op_decrypt_verify_start): Likewise. + * delete.c (gpgme_op_delete_start): Likewise. + * edit.c (gpgme_op_edit_start, gpgme_op_card_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, gpgme_op_export_ext_start) + (gpgme_op_export_keys_start, gpgme_op_export_keys): Likewise. + * genkey.c (gpgme_op_genkey_start): Likewise. + * getauditlog.c (gpgme_op_getauditlog_start): Likewise. + * import.c (gpgme_op_import_start, gpgme_op_import_keys_start): + Likewise. + * opassuan.c (gpgme_op_assuan_transact_start): Likewise. + * sign.c (gpgme_op_sign_start): Likewise. + * verify.c (gpgme_op_verify_start): Likewise. + * vfs-create.c (gpgme_op_vfs_create): Likewise. + * vfs-mount.c (gpgme_op_vfs_mount): Likewise. + +2009-11-04 Marcus Brinkmann <marcus@g10code.de> + + * ath.h (ath_self): New prototype. Include <stdint.h> + * ath.c, ath-pth.c, ath-pthread.c (ath_self): New function. + * debug.h: Rewrite most macros to beautify debug output. + (_gpgme_debug_buffer): Remove tagname and tag argument. + (_gpgme_debug_frame_begin, _gpgme_debug_frame_end): New prototypes. + * debug.c: Include <time.h>. Don't include assuan.h. + (frame_nr, FRAME_NR): New thread-specific variable and macro. + (debug_init): Do not initialize assuan. Call _gpgme_debug after + initialization instead using printf directly. + (_gpgme_debug): Do not call debug_init (we now ensure proper + initialization by user). Add timestamp and thread/process ID. + (_gpgme_debug_buffer): Do not take tagname and tag argument. + (_gpgme_debug_frame_begin, _gpgme_debug_frame_end): New functions. + * version.c (gpgme_check_version_internal, gpgme_check_version): + Fix debug string. Do not initialize assuan. + * posix-io.c (get_max_fds): Use 0 not NULL (nicer debug output). + +2009-11-04 Werner Koch <wk@g10code.com> + + * gpgme-tool.c (register_commands): Add HELP feature. + +2009-11-03 Werner Koch <wk@g10code.com> + + * gpgme.h.in (GPGME_PROTOCOL_UISERVER): New. + +2009-11-03 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (main_sources): Change g13.c to vfs-mount.c. Add + vfs-create.c + * vfs-create.c: New file. + * g13.c: Renamed to ... + * vfs-mount.c: ... this new file. + * gpgme.h.in (gpgme_op_vfs_create): New prototype. + * gpgme.def, libgpgme.vers: Add gpgme_op_vfs_create. + * gpgme-tool.c (gt_vfs_create, cmd_vfs_create): New functions. + (register_commands): Add VFS_CREATE and CREAET. + +2009-11-02 Marcus Brinkmann <marcus@g10code.de> + + * debug.h (_gpgme_debug_buffer): Make TAG argument const const. + * debug.c (_gpgme_debug_buffer): Likewise. + * gpgme-tool.c (input_notify, output_notify): Adjust type to new + assuan interface. + * decrypt.c (gpgme_op_decrypt_result): Remove unused variable. + * opassuan.c (gpgme_op_assuan_transact): Fix return value. + +2009-10-30 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (noinst_PROGRAMS): New target gpgme-tool. + (gpgme_tool_LDADD): New variable. + * gpgme-tool.c: New file. + * ops.h (_gpgme_sig_notation_clearm _gpgme_signers_clear): New + prototypes. + * gpgme.c (gpgme_set_protocol): Allow GPGME_PROTOCOL_GPGCONF (when + had that gone missing?). + (_gpgme_sig_notation_clear): New function without debug output. + (gpgme_release): Call it and _gpgme_signers_clear. + * signers.c (_gpgme_signers_clear): New function without debug output. + * g13.c (gpgme_op_vfs_mount): Add debug output. + * assuan-support.c (my_spawn): Allow fd_child_list to be NULL. + * conversion.c (_gpgme_encode_percent_string): Fix infinite loop. + * debug.h: Put tag in front of debug lines, should make for nicer + output. + * engine-assuan.c (llass_new): Use our new system hooks for libassuan. + * engine-g13.c (g13_new): Remove redundant assuan context allocation. + * version.c (gpgme_check_version_internal): Delay debug output + until after gpgme_check_version was called. + +2009-10-28 Marcus Brinkmann <marcus@g10code.de> + + * signers.c, encrypt-sign.c, encrypt.c, delete.c, keylist.c, + edit.c, import.c, export.c: Fix last change in debug output. + +2009-10-27 Marcus Brinkmann <marcus@g10code.de> + + * edit.c (gpgme_op_edit_start, gpgme_op_edit) + (gpgme_op_card_edit_start, gpgme_op_card_edit): Add debug output. + * encrypt-sign.c (gpgme_op_encrypt_sign_start) + (gpgme_op_encrypt_sign): Likewise. + * encrypt.c (gpgme_op_encrypt_start, gpgme_op_encrypt) + (gpgme_op_encrypt_result): Likewise. + * export.c (gpgme_op_export_start, gpgme_op_export) + (gpgme_op_export_ext_start, gpgme_op_export_ext) + (gpgme_op_export_keys_start, gpgme_op_export_keys): Likewise. + * genkey.c (gpgme_op_genkey_start, gpgme_op_genkey) + (gpgme_op_genkey_result): Likewise. + * getauditlog.c (gpgme_op_getauditlog_start) + (gpgme_op_getauditlog): Likewise. + * import.c (gpgme_op_import_result, gpgme_op_import_start) + (gpgme_op_import): Likewise. + * keylist.c (gpgme_op_keylist_result, keylist_colon_handler) + (gpgme_op_keylist_start, gpgme_op_keylist_ext_start) + (gpgme_op_keylist_next, gpgme_op_keylist_end, gpgme_get_key): Likewise. + * opassuan.c (gpgme_op_assuan_transact_start) + (gpgme_op_assuan_transact_ext, gpgme_op_assuan_result) + (gpgme_op_assuan_transact): Likewise. + * signers.c (gpgme_signers_add, gpgme_signers_clear): Likewise. + * trustlist.c (gpgme_op_trustlist_start) + (gpgme_op_trustlist_next, gpgme_op_trustlist_end): Likewise. + * verify.c (gpgme_op_verify_start, gpgme_op_verify) + (gpgme_op_verify_result): Likewise. + +2009-10-26 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in (struct gpgme_io_event_done_data) + (gpgme_io_event_done_data_t): New types. + (struct _gpgme_op_assuan_result): Deprecate the err member. + (gpgme_op_assuan_result): Deprecate (for now). + (gpgme_op_assuan_transact_ext): New prototype. + (gpgme_op_assuan_transact): Deprecate. + (struct _gpgme_op_g13_result): Replace with ... + (struct _gpgme_op_vfs_mount_result): ... this. + (gpgme_op_g13_mount): Replace with ... + (gpgme_op_vfs_mount): ... this. + * gpgme.def (gpgme_op_assuan_transact_ext, gpgme_wait_ext) + (gpgme_op_vfs_mount_result, gpgme_op_vfs_mount): New. + (gpgme_op_g13_mount): Remove. + * libgpgme.vers: Likewise. + * engine-backend.h (struct engine_ops): Remove RESULT_CB and + RESULT_CB_VALUE args in opassuan_transact member. Add CANCEL_OP + member. + * ops.h (_gpgme_cancel_with_err, _gpgme_wait_on_condition): Add + OP_ERR argument. + (_gpgme_wait_one_ext): New prototype. + * context.h (ctx_op_data_id_t): Add OPDATA_VFS_MOUNT. + * engine-g13.c (g13_cancel_op): New function. + (parse_status): Remove declaration. + (g13_assuan_simple_command): Do nothing with status lines for now. + (status_handler): Update opaque value access. + (_gpgme_engine_ops_g13): Add new cancel_op member. + * gpgme.c (_gpgme_cancel_with_err): Add new parameter OP_ERR. + Handle operational errors. + (gpgme_cancel, gpgme_io_read, gpgme_io_write): Add debug output. + * data.c (_gpgme_data_inbound_handler) + (_gpgme_data_outbound_handler): Adjust opaque value access. + * engine-gpg.c (command_handler, status_handler) + (colon_line_handler): Likewise. + * engine-gpgsm.c (status_handler): Likewise. + * engine-gpg.c (_gpgme_engine_ops_gpg): Add cancel_op member. + * engine-gpgsm.c (_gpgme_engine_ops_gpgsm): Likewise. + * g13.c: Rewritten (and will be rewritten again). + * engine.h (_gpgme_engine_op_assuan_transact): Remove result_cb + and result_cb_value parameters from prototype. + (_gpgme_engine_cancel_op): New prototype. + * engine.c (engine_ops) [! ENABLE_ASSUAN]: Add missing comma. + (_gpgme_engine_op_assuan_transact): Remove result_cb and + result_cb_value parameter. + (_gpgme_engine_cancel_op): New function. + * wait.h (_gpgme_run_io_cb): Add new argument OP_ERR. + (struct io_cb_data): New struct to pass opaque data and get a + op_err return value. Needed because we can't modify I/O callback + handler signature because it is exposed to the user. + * wait.c (_gpgme_run_io_cb): Add OP_ERR parameter. Handle + operational errors. + * wait-user.c (_gpgme_user_io_cb_handler): Handle operational + errors. + * wait-private.c (_gpgme_wait_on_condition): New argument to + retrieve the operational result. Handle operational errors in + session based protocols. + (_gpgme_wait_one_ext): New function. + (_gpgme_wait_one): Pass argument in invocation of + _gpgme_wait_on_condition. + * wait-global.c (struct ctx_list_item): Add member OP_ERR. + (ctx_done): New argument OP_ERR. + (ctx_wait): New argument OP_ERR. + (gpgme_wait_ext): New function based on gpgme_wait but handling + operational errors. + (gpgme_wait): Implement in term of gpgme_wait_ext. + * keylist.c (gpgme_op_keylist_next): Pass argument in invocation + of _gpgme_wait_on_condition. + * trustlist.c (gpgme_op_trustlist_next): Pass argument in + invocation of _gpgme_wait_on_condition. + * engine-assuan.c (struct engine_llass): Replace members RESULT_CB + and RESULT_CB_VALUE by LAST_OP_ERR. + (_gpgme_engine_assuan_last_op_err): Add this hack function. + (llass_cancel_op): New function. + (_gpgme_engine_llass_ops): Add cancel_op member. + (llass_status_handler): Update opaque value access. + (llass_transact): Remove RESULT_CB and RESULT_CB_VALUE arguments. + * opassuan.c: Move compat hacks to the end of file. + (opassuan_start): Do not set OPD->result.err. + Do not pass RESULT_Cb and CTX to _gpgme_engine_op_assuan_transact. + (gpgme_op_assuan_transact_ext): New function. + + * debug.h (DEBUG_GLOBAL): New debug level. + * conversion.c (gnupg_errors, _gpgme_map_gnupg_error): Removed. + * data-user.c (gpgme_data_new_from_cbs): Add debug output. + * data-fd.c (gpgme_data_new_from_fd): Likewise. + * data-stream.c (gpgme_data_new_from_stream): Likewise. + * decrypt.c (gpgme_op_decrypt_result, gpgme_op_decrypt_start) + (gpgme_op_decrypt): Likewise. + * delete.c (gpgme_op_delete_start, gpgme_op_delete): Likewise. + * decrypt-verify.c (gpgme_op_decrypt_verify_start) + (gpgme_op_decrypt_verify): Likewise. + * sign.c (gpgme_op_sign_result): Fix debug message. + * data-mem.c (gpgme_data_new): Improve debug output. + * verify.c (parse_trust): Use atoi instead of + _gpgme_map_gnupg_error. + * decrypt.c (_gpgme_decrypt_status_handler): Likewise. + +2009-10-22 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am: Remove @NETLIBS@ from LIBADDs. + (g13_components): New variable. + (main_sources): Add $(g13_components). + * g13.c, engine-g13.c: New files. + * engine.c (engine_ops): Check for assuan for assuan engine, add + g13 engine. + * util.h (_gpgme_get_g13_path, _gpgme_encode_percent_string): New + prototypes. + * conversion.c (_gpgme_encode_percent_string): New function. + * gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_G13. + (struct _gpgme_op_g13_result, gpgme_g13_result_t): New types. + (gpgme_op_g13_mount): New function. + * gpgme.def, libgpgme.vers: Add gpgme_op_g13_mount. + * gpgme.c (gpgme_set_protocol): Allow GPGME_PROTOCOL_G13. + (gpgme_get_protocol_name): Add GPGME_PROTOCOL_G13. + * posix-util.c (_gpgme_get_g13_path): New function. + * w32-util.c (_gpgme_get_g13_path): New function. + * engine-backend.h (_gpgme_engine_ops_g13): New declaration. + +2009-10-20 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-config.in (netlibs): Remove. + (assuan_cflags, assuan_libs): Add. + + * Makefile.am (assuan_cppflags, assuan_libobjs): Removed. + (gpgsm_components): Move engine-assuan.c to ... + (assuan_components): ... this new variable. + (main_sources): Add this new variable. + (AM_CPPFLAGS): Remove $(assuan_cppflags). + (AM_CFLAGS): Add @LIBASSUAN_CFLAGS@. + (libgpgme_la_DEPENDENCIES, libgpgme_pth_la_DEPENDENCIES) + (libgpgme_glib_la_DEPENDENCIES, libgpgme_qt_la_DEPENDENCIES) + (libgpgme_pthread_la_DEPENDENCIES): Remove $(assuan_libobjs). + (libgpgme_la_LIBADD, libgpgme_pth_la_LIBADD) + (libgpgme_glib_la_LIBADD, libgpgme_qt_la_LIBADD)) + (libgpgme_pthread_la_LIBADD): Replace $(assuan_libobjs) by + @LIBASSUAN_LIBS@. + * priv-io.h [!HAVE_W32_SYSTEM]: Declare _gpgme_io_recvmsg, + _gpgme_io_sendmsg, _gpgme_io_waitpid. + * engine-backend.h: Define with [ENABLE_ASSUAN] instead + of [ENABLE_GPGSM]. + * posix-io.c (_gpgme_io_waitpid): Make non-static. + * util.h (ENABLE_ASSUAN): Declar _gpgme_assuan_system_hooks, + _gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb. + * engine-gpgsm.c: Don't map assuan error codes. Use + assuan_release instead of assuan_disconnect. + (map_assuan_error): Remove function. + (gpgsm_new): Use new assuan context interface. + * engine-assuan.c: Use assuan_release instead of + assuan_disconnect. + (llass_new): Use new assuan context interface. + +2009-10-07 <wk@g10code.com> + + * priv-io.h [W32]: Include windows.h instead of sys/socket.h. + +2009-08-06 Werner Koch <wk@g10code.com> + + * op-support.c (_gpgme_parse_inv_recp): Allow for no fingerprint. + + * engine-gpgsm.c (gpgsm_sign): Hook up the status func for the + SIGNER command. + * gpgme.h.in (GPGME_STATUS_INV_SGNR, GPGME_STATUS_NO_SGNR): New. + * sign.c (op_data_t): Add fields IGNORE_INV_RECP and INV_SGNR_SEEN. + (_gpgme_op_sign_init_result): Factor code out to ... + (sign_init_result): .. new. Init new fields. + (sign_start): Use sign_init_result. + (_gpgme_sign_status_handler): Take care of the new INV_SGNR. + Return an error if no signature has been created. + +2009-07-07 Werner Koch <wk@g10code.com> + + * engine-gpgsm.c (struct engine_gpgsm): Add fields + input_helper_data and input_helper_memory. + (close_notify_handler): Release these new fields. + (gpgsm_import): Implement the keyarray feature. + + * engine-gpg.c (gpg_import): Actually return GPG_ERR_INV_VALUE. + + * engine-gpgsm.c (gpgsm_import): Return an error for unknown data + encodings. + +2009-06-22 Marcus Brinkmann <marcus@g10code.de> + + * debug.h: Everywhere, use %p instead of 0x%x to print pointer. + [HAVE_STDINT_H]: Include <stdint.h>. + (_TRACE, TRACE, TRACE0, TRACE1, TRACE2, TRACE3, TRACE6): Cast tag + to (uintptr_t) before casting it to (void*) to silence GCC + warning. + + * gpgme.h.in (_GPGME_DEPRECATED_OUTSIDE_GPGME): New macro. + * sign.c (_GPGME_IN_GPGME): Define it. + * keylist.c (_GPGME_IN_GPGME): Define it. + + * debug.c (_gpgme_debug_begin, _gpgme_debug_add): Handle error in + vasprintf and asprintf. + + * priv-io.h: Include <sys/socket.h>. Declare _gpgme_io_connect. + +2009-06-18 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in (GPGME_CONF_PATHNAME): Revert last change, it's + back! (GPA still uses it...). + + * gpgme.def: Fix stupid typo. + * w32-io.c (_gpgme_io_pipe): Add missing declaration. + + * gpgme.h.in (GPGME_CONF_PATHNAME): Remove obsolete macro. + + * w32-io.c (_gpgme_io_pipe): Allocate reader/writer thread right + away. + (_gpgme_io_read, _gpgme_io_write, _gpgme_io_select) + (_gpgme_io_dup): Never allocate threads here. + (find_writer, find_reader): Check return value of thread creation + function. + + * context.h (CTX_OP_DATA_MAGIC): New macro. + (struct ctx_op_data): New member MAGIC. + * op-support.c (_gpgme_op_data_lookup): Initialize magic. + * gpgme.c (gpgme_result_unref, gpgme_result_ref): Check magic. + +2009-06-16 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_result_unref): Hot fix to release a lock. + + * gpgme.c (result_ref_lock): New global variable. + (gpgme_result_ref, gpgme_result_unref): use it. + +2009-06-16 Werner Koch <wk@g10code.com> + + * version.c: Include stdlib.h. + + * gpgme.h.in (gpgme_data_encoding_t): Add GPGME_DATA_ENCODING_URL, + GPGME_DATA_ENCODING_URLESC, GPGME_DATA_ENCODING_URL0. + * data.c (gpgme_data_set_encoding): Adjust for new values. + * engine-gpg.c (string_from_data): New. + (gpg_import): Implement --fetch-key feature. + + * gpgme.h.in (gpgme_op_export_keys_start, gpgme_op_export_keys): New. + * gpgme.def, libgpgme.vers: Add them. + * export.c (gpgme_op_export_keys_start, gpgme_op_export_keys): New. + (export_keys_start): New. + + * gpgme.h.in (gpgme_export_mode_t, GPGME_EXPORT_MODE_EXTERN): New. + (gpgme_op_export_start, gpgme_op_export, gpgme_op_export_ext_start) + (gpgme_op_export_ext): Change arg RESERVED to MODE of new + compatible type. + * export.c (gpgme_export_ext_start, gpgme_op_export) + (gpgme_op_export_ext_start, gpgme_op_export_ext): Ditto. + (export_start): Ditto. + * engine.c (_gpgme_engine_op_export): Ditto. + * engine-backend.h (struct engine_ops): Ditto. + * engine-gpgsm.c (gpgsm_export, gpgsm_export_ext): Ditto. + * engine-gpg.c (gpg_export, gpg_export_ext): Ditto. Implement + mode EXTERN. + (gpg_export, gpg_export_ext): Factor common code out to .. + (export_common): .. this. + + * gpgme.h.in (gpgme_op_import_keys_start, gpgme_op_import_keys): New. + * gpgme.def, libgpgme.vers: Add them. + * import.c (gpgme_op_import_keys_start, gpgme_op_import_keys): New. + (_gpgme_op_import_keys_start): New. + * engine.c (_gpgme_engine_op_import): Add arg KEYARRAY. + * engine-backend.h (struct engine_ops): Ditto. + * engine-gpgsm.c (gpgsm_import): Ditto. Not functional. + * engine-gpg.c (gpg_import): Ditto. Implement it. + +2009-06-15 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in (gpgme_result_ref, gpgme_result_unref): Add + prototypes. + * gpgme.def, libgpgme.vers (gpgme_result_ref, gpgme_result_unref): + Add these. + * context.h (struct ctx_op_data): Add member "references". + * gpgme.c (gpgme_result_ref, gpgme_result_unref): New functions. + (_gpgme_release_result): Use gpgme_result_unref. + * op-support.c (_gpgme_op_data_lookup): Initialize references. + +2009-06-12 Werner Koch <wk@g10code.com> + + * gpgme-w32spawn.c (translate_get_from_file): Parse optional spawn + flags. Add new arg R_FLAGS. Fix segv on file w/o LF. + (translate_handles): Add new arg R_FLAGS. Avoid possible segv. + (main): Pass flags for my_spawn. + (my_spawn): Add arg FLAGS and implement AllowSetForegroundWindow. + + * priv-io.h (IOSPAWN_FLAG_ALLOW_SET_FG): New. + * w32-io.c (_gpgme_io_spawn): Add arg FLAGS and implement it. + * w32-glib-io.c (_gpgme_io_spawn): Ditto. + * w32-qt-io.cpp (_gpgme_io_spawn): Ditto. + * posix-io.c (_gpgme_io_spawn): Add dummy arg FLAGS. + * engine-gpg.c (start): Call spawn with new flag. + + * w32-util.c (_gpgme_allow_set_foregound_window): Rename to + _gpgme_allow_set_foreground_window. Change all callers. + * posix-util.c (_gpgme_allow_set_foreground_window): Ditto. + +2009-06-10 Werner Koch <wk@g10code.com> + + * w32-util.c (_gpgme_allow_set_foregound_window): Add trace support. + +2009-06-09 Werner Koch <wk@g10code.com> + + * engine-gpg.c (gpg_io_event): Test for cmd.fd. + + * version.c (gpgme_check_version_internal): Make result const. + + * gpgme.c: Include priv-io.h. + (gpgme_io_read, gpgme_io_write): New. + * libgpgme.vers (GPGME_1.1): Add them. + * gpgme.def: Ditto. + + * Makefile.am (main_sources): Remove gpgme.h. + (include_HEADERS): Rename to nodist_include_HEADERS so that a + VPATH build won't use the distributed one. + + * util.h (GPG_ERR_NOT_OPERATIONAL): Define. + +2009-05-28 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in (gpgme_check_version_internal): New prototype. + (gpgme_check_version): New macro, overriding function of the same + name. + * libgpgme.vers, gpgme.def: Add gpgme_check_version_internal.o + * context.h (_gpgme_selftest): New variable declaration. + * version.c: Include "context.h". + (gpgme_check_version): Set _gpgme_selftest on success. + (gpgme_check_version_internal): New function. + * gpgme.c (_gpgme_selftest): Define it. + (gpgme_new): Check the selftest result. + +2009-05-18 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in (gpgme_encrypt_flags_t): Add + GPGME_ENCRYPT_NO_ENCRYPT_TO. + * engine-gpg.c (gpg_encrypt): Pass --no-encrypt-to to gpg if + GPGME_ENCRYPT_NO_ENCRYPT_TO flag is set. + +2009-05-14 Werner Koch <wk@g10code.com> + + * gpgme.h.in (gpgme_status_code_t): Explicitly initialize for + better maintainability and to help debugging. + +2009-05-05 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h.in: Add compile time check for _FILE_OFFSET_BITS. + +2009-04-15 Marcus Brinkmann <marcus@g10code.de> + + * posix-io.c (_gpgme_io_socket, _gpgme_io_connect): New functions. + * w32-io.c (_gpgme_io_connect): Fix stupid error. + +2009-04-08 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (giochannel_table): New members used, fd, socket. + (find_channel): Drop CREATE argument. + (new_dummy_channel_from_fd, new_channel_from_fd) + (new_channel_from_socket): New functions. + (_gpgm_io_fd2str): Implement for sockets. + (_gpgme_io_write, _gpgme_io_read): Translate EAGAIN errors + correctly. + (_gpgme_io_pipe): Fix for new channel bookkeeping. + (_gpgme_io_close, _gpgme_io_dup): Likewise. + (wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New. + * w32-io.c (MAX_READERS, MAX_WRITERS): Bump up to 40. + (wsa2errno, _gpgme_io_socket, _gpgme_io_connect): New. + * w32-qt-io.cpp (_gpgme_io_socket, _gpgme_io_connect): New stubs. + * version.c [HAVE_W32_SYSTEM]: Include "windows.h. + (do_subsystem_inits) [HAVE_W32_SYSTEM]: Call WSAStartup. + * engine-assuan.c (llass_status_handler): Ignore EAGAIN errors. + +2009-03-18 Werner Koch <wk@g10code.com> + + * gpgme.h.in (GPGME_KEYLIST_MODE_EPHEMERAL): New. + * engine-gpgsm.c (gpgsm_keylist): Send new option. + +2009-03-13 Werner Koch <wk@g10code.com> + + * gpgme-config.in: Make sure locale is set to C. + +2009-02-24 Werner Koch <wk@g10code.com> + + * gpgme.h.in (struct _gpgme_op_assuan_result): New. + (gpgme_assuan_result_t): New. + (gpgme_op_assuan_result): Change return type. + (struct _gpgme_assuan_sendfnc_ctx) + (gpgme_assuan_sendfnc_ctx_t, gpgme_assuan_sendfnc_t):Remove. + (gpgme_assuan_inquire_cb_t): Changed. + * opassuan.c (op_data_t): Make use of a result structure. + (gpgme_op_assuan_result): Change return type. + (opassuan_start): Use result structure. + (result_cb): Ditto. + * engine-assuan.c (struct _gpgme_assuan_sendfnc_ctx): Remove. + (inquire_cb_sendfnc): Remove. + (inquire_cb): Change for new callback scheme. Not yet finished. + (llass_status_handler): Allow sending a CANCEL from the inquire CB. + +2009-02-04 Werner Koch <wk@g10code.com> + + * w32-glib-io.c (_gpgme_io_spawn): Make ARGV argument const to + match prototype. + * w32-qt-io.cpp (_gpgme_io_spawn): Ditto. + +2009-02-03 Werner Koch <wk@g10code.com> + + * gpgme.h.in (struct _gpgme_subkey): Add fields IS_CARDKEY and + CARD_NUMBER.. + * key.c (gpgme_key_unref): Release field CARD_NUMBER. + * keylist.c (keylist_colon_handler): Factor common code out to ... + (parse_sec_field15): New. Set card number. + +2009-01-26 Werner Koch <wk@g10code.com> + + * opassuan.c, dirinfo.c, engine-assuan.c: New. + * Makefile.am: Add them. + * engine-backend.h: Add _gpgme_engine_ops_assuan. + (struct engine_ops): Add field OPASSUAN_TRANSACT. Update all + engine intializers. + * Makefile.am (gpgsm_components): Add engine-assuan.c. + * gpgme.h.in (gpgme_protocol_t): Add GPGME_PROTOCOL_ASSUAN. + (gpgme_assuan_data_cb_t, gpgme_assuan_sendfnc_ctx_t) + (gpgme_assuan_inquire_cb_t, gpgme_assuan_status_cb_t): New. + (gpgme_op_assuan_transact_start, gpgme_op_assuan_transact): New. + * gpgme.c (gpgme_get_protocol_name): Ditto. + (gpgme_set_protocol): Support it. + * engine.c (gpgme_get_engine_info): Ditto. + (engine_ops): Register it. + (_gpgme_engine_op_assuan_transact): New. + * libgpgme.vers (gpgme_op_assuan_transact_start) + (gpgme_op_assuan_transact): New. + * gpgme.def (gpgme_op_assuan_transact_start) + (gpgme_op_assuan_transact): New. + * engine-backend.h (struct engine_ops): Add GET_HOME_DIR and + initialize to NULL for all engines. + * engine.c (engine_get_home_dir): New. + (gpgme_get_engine_info): Use it. + (_gpgme_set_engine_info): Use it. + * engine.h (engine_assuan_result_cb_t): New. + * context.h (ctx_op_data_id_t): Add OPDATA_ASSUAN. + + * util.h (GPG_ERR_UNFINISHED): Define if not yet defined. + + * version.c (gpgme_check_version): Protect trace arg against NULL. + +2009-01-19 Werner Koch <wk@g10code.com> + + * rungpg.c: Rename to engine-gpg.c + * Makefile.am (main_sources): Ditto. + +2008-12-03 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (status-table.h): Use $(builddir) to find gpgme.h. + +2008-11-18 Werner Koch <wk@g10code.com> + + * version.c (do_subsystem_inits): Always initialize I/O + subsystem. Fixes regression from 2007-08-02. + + * decrypt.c (_gpgme_decrypt_status_handler): Use + _gpgme_map_gnupg_error to parse the error code for decrypt.algorithm. + +2008-10-30 Marcus Brinkmann <marcus@g10code.de> + + * wait-private.c (_gpgme_wait_on_condition): Remove unused + variable IDX. + * wait-global.c: Include ops.h to silence gcc warning. + (_gpgme_wait_global_event_cb): Pass error value directly. + * wait-user.c: Include ops.h to silence gcc warning. + + * posix-io.c (_gpgme_io_spawn): Make ARGV argument const to + silence gcc warning. Cast argument to execv to silence warning. + * w32-io.c (_gpgme_io_spawn): Likewise. + * priv-io.h (_gpgme_io_spawn): Likewise for prototype. + +2008-10-24 Werner Koch <wk@g10code.com> + + * rungpg.c (gpg_keylist_preprocess): Escape backslashes too. + +2008-10-23 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (gpg_keylist_preprocess): Convert percent escaped + string to C coded string. + +2008-10-20 Werner Koch <wk@g10code.com> + + * Makefile.am (EXTRA_DIST): Add gpgme.h.in. + + * gpgme.h: Rename to gpgme.h.in. + * gpgme.h.in (GPGME_VERSION): Use autoconf substitution. + + * posix-io.c: Include sys/uio.h. Fixes bug #818. + +2008-10-18 Marcus Brinkmann <marcus@g10code.com> + + * w32-util.c (find_program_in_registry): Don't define. + (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path) + (_gpgme_get_gpgconf_path): Do not check for fooProgram in the + registry anymore. It is now no longer possible to overwrite the + default location in that way. + +2008-10-17 Werner Koch <wk@g10code.com> + + * w32-glib-io.c (_gpgme_io_fd2str): Use "%d" and not "%ld" to work + around a bug in mingw32. + +2008-09-23 Marcus Brinkmann <marcus@g10code.com> + + * gpgme.c (gpgme_sig_notation_clear): Clear CTX->sig_notations. + Submitted by "Daniel Mueller" <daniel@danm.de> + +2008-09-16 Marcus Brinkmann <marcus@g10code.com> + + * rungpg.c (gpg_new): Don't use errno with ttyname_r. + +2008-08-11 Marcus Brinkmann <marcus@g10code.com> + + * rungpg.c (gpg_cancel): Remove cmd fd before status fd. + * gpgme.c (_gpgme_cancel_with_err): New function. + (gpgme_cancel): Reimplement in terms of _gpgme_cancel_with_err. + * wait-private.c (_gpgme_wait_on_condition): Use + _gpgme_cancel_with_err. + * wait-user.c (_gpgme_user_io_cb_handler): Likewise. + * wait-global.c (_gpgme_wait_global_event_cb, gpgme_wait): Likewise. + +2008-08-08 Marcus Brinkmann <marcus@g10code.com> + + * rungpg.c (command_handler): Remove I/O callback on error, too. + +2008-06-29 Marcus Brinkmann <marcus@g10code.com> + + * gpgme.c (gpgme_cancel_async): Remove unused variable. + +2008-06-27 Marcus Brinkmann <marcus@g10code.de> + + * libgpgme.vers: Add gpgme_cancel_async. + * gpgme.def: Likewise. + + * context.h: Include "sema.h". + (struct gpgme_context): New members lock and canceled. + * gpgme.c (gpgme_new): Initialize lock. + (gpgme_release): Destroy lock. + (gpgme_cancel_async): New function. + * op-support.c (_gpgme_op_reset): Reset the canceled flag. + * wait-global.c (gpgme_wait): Check cancel flag before processing + any I/O callbacks. + * wait-private.c (_gpgme_wait_on_condition): Likewise. + * wait-user.c (_gpgme_user_io_cb_handler): Likewise. + +2008-06-26 Werner Koch <wk@g10code.com> + + * w32-util.c (_gpgme_mkstemp): Replace sprint by stpcpy. + (mkstemp): Need to use GetSystemTimeAsFileTime for better + compatibility. + +2008-06-25 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-w32spawn.c: New file. + * Makefile.am (libexec_PROGRAMS) [HAVE_W32_SYSTEM]: New variable + with gpgme-w32spawn. + * engine-gpgsm.c (gpgsm_new): Use server translated handles. + (gpgsm_set_locale): Return early if locale value is NULL. + * util.h (_gpgme_mkstemp) + (_gpgme_get_w32spawn_path) [HAVE_W32_SYSTEM]: New function + prototypes. + * w32-util.c: Include <stdint.h>, <sys/stat.h> and <unistd.h>. + (letters, mkstemp, _gpgme_mkstemp, _gpgme_get_w32spawn_path): New + functions. + * rungpg.c (gpg_decrypt, gpg_encrypt, gpg_encrypt_sign) + (gpg_genkey, gpg_import, gpg_verify, gpg_sign): Pass data over + special filename FD rather than stdin. + (struct arg_and_data_s): Add member ARG_LOCP. + (struct fd_data_map_s): Add member ARG_LOC. + (struct engine_gpg): Add member ARG_LOC to status and colon. + (_add_arg, add_arg_with_locp): New function. + (add_arg_ext): Reimplement in terms of _add_arg. + (gpg_new): Remember argument location for status FD. + (build_argv): Set argument location if requested. Also set + argument location of fd_data_map for data items. + (start): Adjust caller of _gpgme_io_spawn. + * priv-io.h (struct spawn_fd_item_s): Add members peer_name and + arg_loc. + (_gpgme_io_spawn): Remove parent fd list argument. + * posix-io.c (get_max_fds): New function. + (_gpgme_io_dup): Add tracing. + (_gpgme_io_spawn): Remove parent fd list. Change meaning of child + fd list to contain all child fds that should be inherited. Close + all other file descriptors after fork. + * w32-io.c, w32-glib-io.c, w32-qt-io.c(_gpgme_io_spawn): Remove + parent fd list. Change meaning of child fd list to contain all + child fds that should be inherited. Do not inherit any file + descriptors, but DuplicateHandle them. Spawn process through + wrapper process. Provide wrapper process with a temporary file + containing handle translation data. Return translated handle + names. + * w32-io.c (reader): Add more tracing output. + (_gpgme_io_read): Likewise. + * engine-gpgconf.c (gpgconf_read): Adjust caller of + _gpgme_io_spawn. + * version.c (_gpgme_get_program_version): Likewise. + +2008-06-20 Werner Koch <wk@g10code.com> + + * engine-gpgconf.c (gpgconf_read): Change ARGV initialization for + compatibility with old compilers. Fix amount of memmove. Fix + CR removal. + +2008-06-19 Werner Koch <wk@g10code.com> + + * gpgme.h (GPGME_CONF_PATHNAME): Replace by GPGME_CONF_FILENAME, + change all callers and provide compatibilty macro. + (gpgme_conf_type_t): Add complex types 34..37. + * engine-gpgconf.c (gpgconf_parse_option, arg_to_data) + (_gpgme_conf_arg_new, _gpgme_conf_arg_release): Add new types. + +2008-06-19 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgconf.c (gpgconf_parse_option): Fix comma detection. + +2008-05-09 Werner Koch <wk@g10code.com> + + * engine-gpgconf.c (gpgconf_read): Do not pass empty lines to the + callback. + +2008-05-07 Werner Koch <wk@g10code.com> + + * engine-gpgconf.c (gpgconf_write): Change argv[0] to a + self-explaining string. Needs a proper fix, though. + + * rungpg.c (gpg_keylist, gpg_keylist_ext): Factor common code out + to .. + (gpg_build_keylist_options): .. new. Allow combination of extern + and intern mode. + (gpg_new): DFT_TTYNAME is an array, thus check the first character. + +2008-05-06 Werner Koch <wk@g10code.com> + + * version.c (extract_version_string): New. + (_gpgme_get_program_version): Use it to allow for suffixes in the + version line. + +2008-04-28 Werner Koch <wk@g10code.com> + + * engine-gpgconf.c (gpgconf_read): Fixed segv. Avoid memmove for + each line. + +2008-04-22 Marcus Brinkmann <marcus@g10code.de> + + * w32-qt-io.cpp, kdpipeiodevice.cpp: New versions from Frank + Osterfeld, implement blocking select. + +2008-03-11 Marcus Brinkmann <marcus@g10code.de> + + * data.c (gpgme_data_read, gpgme_data_write): Retry on EINTR. + +2008-03-06 Marcus Brinkmann <marcus@g10code.de> + + * key.c (_gpgme_key_add_sig): Terminate UID in case SRC is NULL. + Reported by Marc Mutz. + +2008-03-05 Marcus Brinkmann <marcus@g10code.de> + + * decrypt.c (release_op_data): Release OPD->result.recipients. + * encrypt.c (release_op_data): Release invalid_recipient. + +2008-02-15 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgconf.c (gpgconf_read): Fix end-of-line handline. + +2008-02-14 Werner Koch <wk@g10code.com> + + * w32-io.c (_gpgme_io_spawn): Add arg R_PID to return the pid. + * posix-io.c (_gpgme_io_spawn): Ditto. + * w32-glib-io.c (_gpgme_io_spawn): Ditto. + * w32-qt-io.cpp (_gpgme_io_spawn): Ditto. + * priv-io.h (_gpgme_io_spawn): Adjust prototyp and change all callers. + * rungpg.c (start): Call _gpgme_allow_set_foregound_window. + + * w32-util.c (_gpgme_allow_set_foregound_window): New. + * posix-util.c (_gpgme_allow_set_foregound_window): New. + * engine-gpgsm.c (default_inq_cb): New. + (gpgsm_new) [W32]: Enable pinentry notifications. + (status_handler): Handle inquiries. + +2008-01-30 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp: New version by Frank Osterfeld, fixes race + condition. + +2008-01-28 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (map_input_enc): Rename to ... + (map_data_enc): ... this. Also change all callers. + (gpgsm_encrypt, gpgsm_export, gpgsm_export_ext, gpgsm_genkey) + (gpgsm_sign): Set encoding for output. + +2008-01-28 Werner Koch <wk@g10code.com> + + * keylist.c (gpgme_get_key): Skip duplicated keys. Fixes bug 876. + +2008-01-14 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgconf.c (gpgconf_config_load_cb): Fix program_name + field. + +2008-01-10 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp: New version from Frank Osterfeld. + + * engine-gpgconf.c (gpgconf_config_load_cb2): Handle the flag + NO_ARG_DESC. + +2008-01-04 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (gpgconf_components): New variable. + (main_sources): Add gpgconf.c. + * gpgme.h (gpgme_protocol_t): New protocol GPGME_PROTOCOL_GPGCONF. + (gpgme_conf_level_t, gpgme_conf_type_t, gpgme_conf_arg_t) + (gpgme_conf_opt_t, gpgme_conf_comp_t, gpgme_conf_arg_new) + (gpgme_conf_arg_release, gpgme_conf_opt_change) + (gpgme_conf_release, gpgme_op_conf_load, gpgme_op_conf_save): New + types. + * gpgconf.c, engine-gpgconf.c: New files. + * engine.h: (_gpgme_engine_op_conf_load, + (_gpgme_engine_op_conf_save): New prototypes. + * op-support.c (_gpgme_op_reset): Ignore not implemented locale + function. + * posix-util.c (_gpgme_get_gpgconf_path): New function. + * w32-util.c (_gpgme_get_gpgconf_path): New function. + * engine-gpgsm.c: + (_gpgme_engine_ops_gpgsm): Add stubs for conf_load and conf_save. + * rungpg.c: + (_gpgme_engine_ops_gpg): Add stubs for conf_load and conf_save. + * gpgme.def: Add new gpgconf related interfaces. + * libgpgme.vers: Likewise. + * util.h (_gpgme_get_gpgconf_path): New prototype. + * gpgme.h (gpgme_protocol_t): Add GPGME_PROTOCOL_GPGCONF. + * engine-backend.h (_gpgme_engine_ops_gpgconf): New prototype. + (struct engine_ops): Add members for conf_load and conf_save. + * engine.c (engine_ops): Add _gpgme_engine_ops_gpgconf. + (_gpgme_engine_op_conf_load, + (_gpgme_engine_op_conf_save): New functions. + (gpgme_get_engine_info): Allow protocol GPGME_PROTOCOL_GPGCONF. + +2007-11-28 Marcus Brinkmann <marcus@g10code.de> + + * w32-util.c (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): Search + for installation directory. Remove old fallback default. + (find_program_in_inst_dir): New function. + +2007-11-26 Werner Koch <wk@g10code.com> + + * engine-gpgsm.c (struct engine_gpgsm): Add field INLINE_DATA and + always reset it before calling start. + (gpgsm_new): Clear it. + (status_handler): Implement it. + (gpgsm_getauditlog) [USE_DESCRIPTOR_PASSING]: Use INLINE_DATA. + +2007-11-23 Werner Koch <wk@g10code.com> + + * op-support.c (_gpgme_op_reset): Implement a no-reset flag. + * getauditlog.c (getauditlog_start): Use that flag. + +2007-11-20 Werner Koch <wk@g10code.com> + + * op-support.c (_gpgme_parse_inv_recp): Add new reason code 11. + +2007-11-22 Werner Koch <wk@g10code.com> + + * gpgme.h (gpgme_op_getauditlog_start, gpgme_op_getauditlog): New. + * libgpgme.vers: Ditto. + * gpgme.def: Ditto. + * getauditlog.c: New. + * engine-backend.h (struct engine_ops): Add member GETAUDITLOG. + * engine-gpgsm.c (gpgsm_getauditlog): New. + (_gpgme_engine_ops_gpgsm): Insert new function. + (gpgsm_new): Try to enable audit log support. + * rungpg.c (_gpgme_engine_ops_gpg): Insert dummy entry. + +2007-11-12 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp: New version from Frank Osterfeld. + +2007-10-11 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp: New version from Frank Osterfeld. + +2007-10-09 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp: New version from Frank Osterfeld and Marc + Mutz. + +2007-10-05 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp, w32-qt-io.cpp: New versions from Frank + Osterfeld. + +2007-10-04 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.h, kdpipeiodevice.cpp, kdpipeiodevice.moc, + w32-qt-io.cpp: New versions from Frank Osterfeld. + +2007-10-02 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.cpp, kdpipeiodevice.moc: New versions. + * w32-qt-io.cpp (_gpgme_io_fd2str): Print actual_fd if available. + (_gpgme_io_dup): Only acquire a reference, do not actually dup. + Submitted by Frank Osterfeld. + + * priv-io.h, engine-gpgsm.c: Add comments. + * w32-qt-io.cpp (_gpgme_io_select): Remove code handling frozen FDs. + * w32-glib-io.c (_gpgme_io_close): Always dereference the channel, + even if not primary. + (_gpgme_io_dup): Acquire a reference. Replace unused + implementation by assertion. + +2007-09-28 Werner Koch <wk@g10code.com> + + * engine-gpgsm.c (iocb_data_t): Add SERVER_FD_STR. + (gpgsm_new): Set it. + (gpgsm_set_fd): Use it. + + * w32-glib-io.c (find_channel): Add a new primary flag. + (_gpgme_io_close): Close channel only if primary. + (_gpgme_io_dup): Put newfd into the table as shallow copy. + + * priv-io.h (struct io_select_fd_s): Remove member FROZEN. + * w32-io.c (_gpgme_io_select): Ditto. + * w32-glib-io.c (_gpgme_io_select): Ditto. + + * posix-io.c (_gpgme_io_select): Ditto. + * rungpg.c (read_status): Ditto. + * wait.c (fd_table_put): Ditto. + + * rungpg.c (gpg_io_event): Add tracing. + (start): Use gpg_io_event for sending the start event. + * engine-gpgsm.c (gpgsm_io_event): Add tracing. + (start): Use gpgsm_io_event for sending the start event. + * wait.c (_gpgme_add_io_cb, _gpgme_run_io_cb): Add tracing. + +2007-09-28 Marcus Brinkmann <marcus@g10code.de> + + * kdpipeiodevice.moc, w32-qt-io.cpp, kdpipeiodevice.cpp: New + versions from Frank Osterfeld. + +2007-09-27 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (_gpgme_io_spawn), + w32-qt-io.cpp (_gpgme_io_spawn), w32-io.c (_gpgme_io_spawn): Close + the process handle, return 0. + + * gpgme.h (gpgme_protocol_t): Add GPGME_PROTOCOL_UNKNOWN. + * gpgme.c (gpgme_get_protocol_name): Implement support for + GPGME_PROTOCOL_UNKNOWN. + + * kdpipeiodevice.h: Fix last change. + + * w32-glib-io.c (_gpgme_io_pipe), w32-qt-io.c (_gpgme_io_pipe), + w32-io.c (_gpgme_io_pipe), posix-io.c (_gpgme_io_pipe): Fix debug + output. + +2007-09-25 Marcus Brinkmann <marcus@g10code.de> + + * conversion.c, keylist.c: Include <sys/types.h>. + + * kdpipeiodevice.h: Use namespace _gpgme_. + * kdpipeiodevice.cpp: Use namespace _gpgme_. + [Q_OS_WIN32 && NOMINMAX]: Do not define NOMINMAX again. + * w32-qt-io.cpp: Change namespace of KDPipeIODevice to + _gpgme_::KDPipeIODevice. + +2007-09-17 Werner Koch <wk@g10code.com> + + * rungpg.c (gpg_new): Make robust against undefined ttyname or + ttytype. + +2007-09-14 Werner Koch <wk@g10code.com> + + * data-mem.c (gpgme_data_release_and_get_mem): Fix tracing bug. + +2007-09-14 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_release): Call gpgme_sig_notation_clear. + +2007-09-13 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (gpg_new): Handle return value of _gpgme_getenv (fixes + small memory leak). + +2007-09-07 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (libgpgme_qt_la_SOURCES): Move + moc_kdpipeiodevice.cpp to EXTRA_DIST, as this is only included by + another file (it's more like a header file than a cpp file, but + automake doesn't know that). + + * w32-qt-io.cpp (_gpgme_io_spawn): Fix several cast errors and typos. + * w32-io.c (_gpgme_io_write): Use TRACE_SYSRES instead of TRACE_SYS. + (libgpgme_qt_la_LIBADD): Add QT4_CORE_LIBS, not QT4_CORE_LIB. + + * kdpipeiodevice.h, kdpipeiodevice.cpp, moc_kdpipeiodevice.cpp, + kdpipeiodevice.moc, w32-qt-io.c: New files. + * Makefile.am (ltlib_gpgme_extra): Rename to ltlib_gpgme_glib. + (ltlib_gpgme_qt): New variable. + (lib_LTLIBRARIES): Add $(ltlib_gpgme_qt). + (libgpgme_qt_la_SOURCES): New variable. + (AM_CPPFLAGS): Add @QT4_CORE_INCLUDES@ + (AM_CFLAGS): Add @QT4_CORE_CFLAGS@. + (libgpgme_qt_la_LDFLAGS, libgpgme_qt_la_DEPENDENCIES) + (libgpgme_qt_la_LIBADD): New variables. + + * sema.h (struct critsect_s): Rename "private" to "priv" to make + C++ users happy. Change users. + * posix-sema.c (_gpgme_sema_cs_enter, _gpgme_sema_cs_leave) + (_gpgme_sema_cs_destroy): Likewise. + * w32-sema.c (critsect_init, _gpgme_sema_cs_enter) + (_gpgme_sema_cs_leave, _gpgme_sema_cs_destroy): Likewise. + * w32-glib-io.c (gpgme_get_giochannel): Change return type to + void*. + (gpgme_get_fdptr): New function. + * w32-io.c (gpgme_get_fdptr): New function + * gpgme.def: Add gpgme_get_fdptr. + +2007-08-22 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (_gpgme_io_write): Return early if COUNT is zero. + (writer): Remove superfluous check. + +2007-08-20 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h: Move include of gpg-error.h out of extern "C". + +2007-08-07 Werner Koch <wk@g10code.com> + + * gpgme.h (struct _gpgme_signature): Add member CHAIN_MODEL. + * verify.c (parse_trust): Set Chain_MODEL. + +2007-08-02 Werner Koch <wk@g10code.com> + + * w32-glib-io.c (_gpgme_io_spawn): Use DETACHED_PROCESS flag. + * w32-io.c (_gpgme_io_spawn): Ditto. + (_gpgme_io_write): Map ERROR_NO_DATA to EPIPE. + * debug.c (_gpgme_debug): Enable assuan logging. + (_gpgme_debug_subsystem_init): New. + * version.c (do_subsystem_inits): Disable assuan logging and + initialize the debug system. + (gpgme_check_version): Do not trace before the subsystems are + initialized. + +2007-07-17 Marcus Brinkmann <marcus@g10code.de> + + * debug.c: Include <errno.h> and "debug.h". + (_gpgme_debug): Save and restore ERRNO. + (TOHEX): New macro. + (_gpgme_debug_buffer): New function. + * conversion.c, data-compat.c, data-mem.c, data.c, engine-gpgsm.c, + gpgme.c, keylist.c, posix-io.c, rungpg.c, sign.c, version.c, + w32-io.c, wait.c: Replace DEBUG macros by TRACE_* variants. In + most of these files, add many more tracepoints. + +2007-07-16 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (status_handler): Do not send BYE here. + + * w32-io.c (struct reader_context_s, struct writer_context_s): New + members REFCOUNT. + (create_reader, create_writer): Initialize C->refcount to 1. + (destroy_reader, destroy_writer): Only destroy if C->refcount + drops to 0. + (find_reader, find_writer, kill_reader, kill_writer): Beautify. + * priv-io.h (_gpgme_io_dup): New prototype. + * posix-io.c (_gpgme_io_dup): New function. + * w32-io.c (_gpgme_io_dup): Likewise. + * w32-glib-io.c (_gpgme_io_dup): Likewise. + * engine-gpgsm.c (start): Reverting to version 2007-07-10. + +2007-07-13 Marcus Brinkmann <marcus@g10code.de> + + * data-user.c (user_read, user_write, user_seek): Set errno and + return -1 instead returning the error code directly. + * data-compat.c (old_user_seek): Likewise. + * gpgme.c (gpgme_sig_notation_add): Return error properly. + + * Revert the "close_notify_handler" returns int stuff. Always + close in the _gpgme_io_close implementations. + * engine-gpgsm.c (status_handler): Try to terminate the connection + in case of error. + * w32-io.c (_gpgme_io_read): Return C->error_code in ERRNO. + (_gpgme_io_write): Likewise. + + * priv-io.h (_gpgme_io_set_close_notify): Change type of HANDLER + to _gpgme_close_notify_handler. + (_gpgme_close_notify_handler): New type. + (_gpgme_io_dup): Remove prototype. + * posix-io.c (notify_table, _gpgme_io_set_close_notify): Change + type of HANDLER to _gpgme_close_notify_handler_t. + (_gpgme_io_close): Do not close the FD if handler returns 0. + (_gpgme_io_dup): Remove function. + * w32-io.c (notify_table, _gpgme_io_set_close_notify, + _gpgme_io_close): Change type of HANDLER to + _gpgme_close_notify_handler_t. + (_gpgme_io_close): Do not close the FD if handler returns 0. + (_gpgme_io_dup): Remove function. + * w32-glib-io.c (_gpgme_io_dup): Remove function. + (_gpgme_io_set_close_notify, notify_table): Change type of HANDLER + to _gpgme_close_notify_handler_t. + (_gpgme_io_close): Do not close the FD if handler returns 0. + * rungpg.c (close_notify_handler): Change return type to int, + return 1. + * engine-gpgsm.c (close_notify_handler): Change return type to + int, return 0 for status FD and 1 for all other FDs. + (start): Do not duplicate the status FD. + +2007-07-12 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am: Replace implicite rule by suffix rule. Add + SUFFIXES for that. + +2007-07-12 Werner Koch <wk@g10code.com> + + * version.c (do_subsystem_inits) [W32]: Make sure that the socket + system has been started. + +2007-07-10 Marcus Brinkmann <marcus@g10code.de> + + * priv-io.h (_gpgme_io_dup): New prototype. + * posix-io.c (_gpgme_io_dup): New function. + * w32-io.c (_gpgme_io_dup): Likewise. + * w32-glib-io.c (_gpgme_io_dup): Likewise. + * engine-gpgsm.c (start): Use _gpgme_dup() instead of dup(). + +2007-07-08 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c [HAVE_W32_SYSTEM]: Enable the bunch of the file. + * funopen.c (funopen): Rename to _gpgme_funopen. + +2007-04-30 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_new): Fix error handling for ttyname_r. + * rungpg.c (gpg_new): Likewise. + Submitted by Stephen Tether. + +2007-02-26 Werner Koch <wk@g10code.com> + + * verify.c (op_data_t): New element PLAINTEXT_SEEN. + (_gpgme_verify_status_handler): Return an error if more than one + plaintext has been seen. + (parse_error): New arg SET_STATUS. Also detect it based on an + ERROR status (gpg > 1.4.6). + +2007-01-26 Werner Koch <wk@g10code.com> + + * w32-io.c (build_commandline): Fixed stupid quoting bug. + * w32-glib-io.c (build_commandline): Ditto. + + * rungpg.c (gpg_set_locale): Avoid dangling pointer after free. + + * gpgme-config.in: New options --get-gpg and --get-gpgsm. + +2007-01-18 Marcus Brinkmann <marcus@g10code.de> + + * data.h (_gpgme_data_get_fd): Add prototype. + (gpgme_data_get_fd_cb): New type. + (struct _gpgme_data_cbs): New member get_fd. + * data.c (_gpgme_data_get_fd): New function. + * data-fd.c (fd_get_fd): New function. + (fd_cbs): Add fd_get_fd. + * data-stream.c (stream_get_fd): New function. + (stream_cbs): Add stream_get_fd. + * data-mem.c (mem_cbs): Add NULL for get_fd callback. + * data-user.c (user_cbs): Likewise. + * engine-gpgsm.c (gpgsm_set_fd) [USE_DESCRIPTOR_PASSING]: Try to + short-cut by passing the data descriptor directly. + +2007-01-17 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (build_commandline): Quote all command line arguments. + * w32-glib-io.c (build_commandline): Likewise. + +2007-01-10 Werner Koch <wk@g10code.com> + + * ttyname_r.c (ttyname_r) [W32]: Return a dummy name. + +2007-01-08 Werner Koch <wk@g10code.com> + + * version.c (do_subsystem_inits): Do assuan init only if building + with Assuan. + * setenv.c: Include assuan-def.h only if building with Assuan + support. + + * op-support.c (_gpgme_op_reset): Set LC_MESSAGES only if + if defined. + * engine-gpgsm.c (gpgsm_set_locale): Ditto. + * rungpg.c (gpg_set_locale): Ditto. + +2006-12-17 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_set_protocol): Shut down the engine when + switching protocols. + (gpgme_ctx_set_engine_info): Likewise for engine info. + * engine.h (_gpgme_engine_reset): New function prototype. + * engine.c (_gpgme_engine_reset): New function. + * engine-backend.h (struct engine_ops): New member RESET. + * rungpg.c (_gpgme_engine_ops_gpg): Add NULL for reset function. + * engine-gpgsm.c (_gpgme_engine_ops_gpgsm) + [USE_DESCRIPTOR_PASSING]: Add gpgsm_reset for reset. + (_gpgme_engine_ops_gpgsm) [!USE_DESCRIPTOR_PASSING]: Add NULL for + reset function. + (gpgsm_reset) [USE_DESCRIPTOR_PASSING]: New function. + * op-support.c (_gpgme_op_reset): Try to use the engine's reset + function if available. + * engine-gpgsm.c (gpgsm_new): Move code to dup status_fd to ... + (start): ... here. + * posix-io.c (_gpgme_io_recvmsg, _gpgme_io_sendmsg): New functions. + + * engine.h (_gpgme_engine_new): Remove arguments lc_ctype and + lc_messages from prototype. + (_gpgme_engine_set_locale): New prototype. + * engine.c (_gpgme_engine_set_locale): New function. + * op-support.c (_gpgme_op_reset): Call _gpgme_engine_set_locale. + * engine-backend.h (struct engine_ops): Add new member SET_LOCALE. + Remove arguments lc_messages and lc_ctype from member NEW. + * engine-gpgsm.c (struct engine_gpgsm): New members lc_ctype_set + and lc_messages_set. + (gpgsm_new): Remove lc_messages and lc_ctype + arguments. + (gpgsm_set_locale): New function. + (_gpgme_engine_ops_gpgsm): Add gpgsm_set_locale. + * rungpg.c (struct engine_gpg): Add new members lc_messages and + lc_ctype. + (gpg_release): Release lc_messages and lc_ctype if set. + (gpg_new): Remove lc_messages and lc_ctype arguments. + (gpg_set_locale): New function. + (_gpgme_engine_ops_gpg): Add gpg_set_locale. + (add_arg): Implement in terms of: + (add_arg_ext): New function. + (start): Set lc-messages and lc-ctype arguments here. + +2006-12-03 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (struct engine_gpgsm): Move members + input_fd_server, output_fd_server, message_fd_server to ... + (iocb_data): ... here (as server_fd). + (close_notify_handler): Reset tags as well. + (gpgsm_new): Implement support for descriptor + passing. + (fd_type_t): New type. + (gpgsm_clear_fd): New function. Use it instead of _gpgsm_io_close + for unused communication channels. + (gpgsm_set_fd): Rewritten to support descriptor passing. All + relevant callers adjusted as well (previously of _gpgme_io_close). + +2006-12-02 Marcus Brinkmann <marcus@g10code.de> + + * version.c: Include "assuan.h". + (do_subsystem_inits): Call assuan_set_assuan_err_source. + +2006-12-01 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (libgpgme_real_la_SOURCES): Rename to main_sources. + (libgpgme_la_SOURCES, libgpgme_pthread_la_SOURCES, + libgpgme_glib_la_SOURCES, libgpgme_pth_la_SOURCES): Add + $(main_sources). + (libgpgme_la_DEPENDENCIES, libgpgme_la_LIBADD, + libgpgme_pthread_la_DEPENDENCIES, libgpgme_pthread_la_LIBADD, + libgpgme_pth_la_DEPENDENCIES, libgpgme_pth_la_LIBADD, + libgpgme_glib_la_DEPENDENCIES, libgpgme_glib_la_LIBADD): Remove + libgpgme-real.la. + (noinst_LTLIBRARIES): Removed. + (libgpgme_glib_la_CFLAGS, libgpgme_pth_la_CFLAGS): Removed. + (AM_CFLAGS): New variable. + +2006-11-30 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c: Replace AssuanError with gpg_error_t and + ASSUAN_CONTEXT with assuan_context_t. + +2006-11-29 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_new): Check return value of + assuan_pipe_connect. + + * rungpg.c: Include <unistd.h>. + (gpg_new): Support --display, --ttyname, --ttytype, --lc-ctype and + --lc-messages. Fixes issue 734. + +2006-10-24 Marcus Brinkmann <marcus@g10code.de> + + * trustlist.c (gpgme_op_trustlist_next): Return error if OPD is + NULL. + +2006-10-23 Marcus Brinkmann <marcus@g10code.de> + + * wait-global.c (gpgme_wait): Unlock CTX_LIST_LOCK while calling + _gpgme_engine_io_event(). + + * keylist.c (gpgme_op_keylist_next): Return error if OPD is NULL. + +2006-09-25 Marcus Brinkmann <marcus@g10code.de> + + * data-mem.c (gpgme_data_release_and_get_mem): Release the data + object properly. + +2006-09-22 Marcus Brinkmann <marcus@g10code.de> + + * keylist.c (keylist_colon_handler): Move debug output after + initialising KEY. + +2006-07-29 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-config.in (Options): Add NETLIBS. + * Makefile.am (libgpgme_la_LIBADD, libgpgme_pthread_la_LIBADD, + libgpgme_pth_la_LIBADD, libgpgme_glib_la_LIBADD): Add NETLIBS. + + * rungpg.c (read_status): Fix comparison disguising as an + assignment. + +2005-03-24 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_set_locale): Remove conditional on + HAVE_W32_SYSTEM, and just check for LC_MESSAGES. + +2006-07-16 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (read_status): Strip potential carriage return. + * genkey.c (get_key_parameter): Skip potential carriage return. + * version.c (_gpgme_get_program_version): Strip potential carriage + return. + + * data.c (gpgme_data_set_file_name): Allow to clear the file name + by passing NULL. + +2006-06-22 Marcus Brinkmann <marcus@g10code.de> + + * keylist.c (gpgme_get_key): Also clone the engine info. + +2006-03-06 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-config.in (cflags_pth): Revert accidential removal of + pthread support with last change. + +2006-02-28 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (O_BINARY) [!O_BINARY]: New macro. + (_gpgme_io_pipe): Open pipes in binary mode. + +2006-02-22 Marcus Brinkmann <marcus@g10code.de> + + * engine.c (gpgme_engine_check_version): Reimplemented to allow + checking the version correctly even after changing the engine + information. Bug reported by Stéphane Corthésy. + + * rungpg.c (read_colon_line): Invoke colon preprocess handler if + it is set. + (colon_preprocessor_t): New type. + (struct engine_gpg): New member colon.preprocess_fnc. + (gpg_keylist_preprocess): New function. + * keylist.c (keylist_colon_handler): Allow short key IDs. + +2006-02-15 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (create_writer): Make C->have_data a manually resetted + event. + (writer): Move code from end of if block to beginning, so it + is also run the first time. + (_gpgme_io_write): Move assert check after error check. Reset + the is_empty event, and also do it eagerly. + (_gpgme_io_select): Unconditionally wait for the is_empty event. + +2006-01-26 Werner Koch <wk@g10code.com> + + * w32-util.c (_gpgme_get_conf_int): New. + * posix-util.c (_gpgme_get_conf_int): New. + * w32-io.c (get_desired_thread_priority): New. + (create_reader, create_writer): Use it here. + +2006-01-04 Werner Koch <wk@g10code.com> + + * debug.h (_gpgme_debug_srcname): New. Use it with the debug macros. + + * w32-glib-io.c (_gpgme_io_set_nonblocking): Add debug + statements. Disable error return for failed nonblocking call. + +2006-01-03 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (_gpgme_io_close): Only close fd if there is no + channel for it. + +2005-12-31 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (find_channel): Set channel to unbuffered. + (_gpgme_io_select): Fix debug output. + +2005-12-23 Werner Koch <wk@g10code.com> + + * gpgme.h (struct _gpgme_signature): Append field PKA_ADDRESS. + * verify.c (release_op_data, _gpgme_verify_status_handler): Set + this field. + +2005-12-20 Werner Koch <wk@g10code.com> + + * gpgme.h (gpgme_status_code_t): Added GPGME_STATUS_PKA_TRUST_BAD + and GPGME_STATUS_PKA_TRUST_GOOD. + (struct _gpgme_signature): New field pka_trust. + * verify.c (_gpgme_verify_status_handler): Set pka_trust. + +2005-12-06 Werner Koch <wk@g10code.com> + + * keylist.c (keylist_colon_handler): Store fingerprints of the + subkeys. Reset the secret flag of subkeys for stub secret keys. + (NR_FIELDS): Bumped up to 16 + +2005-11-27 Marcus Brinkmann <marcus@g10code.de> + + * engine.c (_gpgme_set_engine_info): Use new_file_name in + engine_get_version invocation. Reported by Stéphane Corthésy. + +2005-11-24 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c (_gpgme_io_fd2str): Remove debug printf. + +2005-11-18 Werner Koch <wk@g10code.com> + + * w32-glib-io.c: Include glib.h before windows to avoid a symbol + shadowing warning. + (find_channel): Better use g_io_channel_win32_new_fd instead of + the autodetection function g_io_channel_unix_new. + (_gpgme_io_select): Rewritten. It is now a fully working select + implementation. + +2005-11-18 Marcus Brinkmann <marcus@g10code.de> + + * priv-io.h (_gpgme_io_fd2str): New prototype. + * posix-io.c (_gpgme_io_fd2str): New function. + * w32-io.c (_gpgme_io_fd2str): New function. + * rungpg.c: Use this new function. + * w32-glib-io.c (_gpgme_io_fd2str): Rewrote the file handle code + again. Two's company, three's the musketeers. + + * w32-glib-io.c: Rewrote the file handle code. We don't create + system fds for every handle (doesn't work for inherited handles), + but we create pseudo fds in a private namespace that designate a + handle and potentially a giochannel. + +2005-11-18 Werner Koch <wk@g10code.com> + + * versioninfo.rc.in: Set file version to LT-version + Svn-revision. + +2005-11-17 Marcus Brinkmann <marcus@g10code.de> + + * w32-glib-io.c: New file. + * gpgme.def (gpgme_get_giochannel): Add symbol. + * Makefile.am (system_components) [HAVE_DOSISH_SYSTEM]: Remove + w32-io.c. + (ltlib_gpgme_extra): New variable. + (lib_LTLIBRARIES): Add $(ltlib_gpgme_extra). + (system_components_not_extra): New variable. + (libgpgme_la_SOURCES, libgpgme_pthread_la_SOURCES, + (libgpgme_pth_la_SOURCES): Add $(system_components_not_extra). + (libgpgme_glib_la_LDFLAGS, libgpgme_glib_la_DEPENDENCIES, + (libgpgme_glib_la_LIBADD, libgpgme_glib_la_CFLAGS) + [BUILD_W32_GLIB]: New variables. + * gpgme-config.in (glib): New option. + * gpgme.m4 (AM_PATH_GPGME_GLIB): New macro. + +2005-11-17 Marcus Brinkmann <marcus@g10code.de> + + * priv-io.h (_gpgme_io_waitpid, _gpgme_io_kill): Removed. + * w32-io.c (_gpgme_io_waitpid, _gpgme_io_kill): Removed. + * posix-io.c (_gpgme_io_kill): Removed. + (_gpgme_io_waitpid): Declare static. + +2005-10-24 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (_gpgme_io_spawn): Don't minimize window, hide it. + +2005-10-21 Werner Koch <wk@g10code.com> + + * Makefile.am: Fixed cut+paste problem + +2005-10-20 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am: Build versioninfo.lo, not versioninfo.o. Also, fix + the whole mess. + +2005-10-16 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (gpg_edit): Don't add a key argument if in card edit + mode. + +2005-10-06 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (gpgme.dll gpgme.dll.a): Use $(srcdir) for + gpgme.def. + + * gpgme.h (gpgme_free): New prototype. + * data-mem.c (gpgme_free): New function. + * libgpgme.vers (GPGME_1.1): Add gpgme_free. + * gpgme.def: Add gpgme_free. + +2005-10-02 Marcus Brinkmann <marcus@g10code.de> + + * util.h (_gpgme_decode_percent_string): Add new argument BINARY + to prototype. + * verify.c (parse_notation): Likewise for invocation. + * conversion.c (_gpgme_decode_percent_string): Likewise to + declaration. If set, do not replace '\0' characters with a + printable string. + * gpgme.h (struct _gpgme_key_sig): New field notations. + * ops.h (_gpgme_parse_notation): New prototype. + * sig-notation.c (_gpgme_parse_notation): New function. + * key.c (gpgme_key_unref): Free all signature notations. + * keylist.c (op_data_t): New member tmp_keysig. + (finish_key): Clear OPD->tmp_keysig. + * gpgme.c (gpgme_set_keylist_mode): Remove check. + * rungpg.c (gpg_keylist): Support listing signature notations. + (gpg_keylist_ext): Likewise. + +2005-10-01 Marcus Brinkmann <marcus@g10code.de> + + * engine.h (_gpgme_set_engine_info): Add prototype. + * engine-backend.h (struct engine_ops): Change return type of + get_file_name() to const char * to silence gcc warning. + * engine.c (engine_get_file_name): Change return type to const + char * to silence gcc warning. + (gpgme_get_engine_info): Use transitional variable to go from + const char * to char * to silence gcc warning. + (_gpgme_set_engine_info): Likewise. + * engine-gpgsm.c (struct engine_gpgsm): Change type of LINE to + char * to silence gcc warning. + (gpgsm_new): Make ARGV a pointer to const char. + (status_handler): Change type of SRC, END, DST, ALINE and NEWLINE + to char * to silence gcc warning. + + * gpgme.def: Add gpgme_data_set_file_name, + gpgme_data_get_file_name, gpgme_sig_notation_clear, + gpgme_sig_notation_add and gpgme_sig_notation_get. + * libgpgme.vers: Add gpgme_sig_notation_clear, + gpgme_sig_notation_add and gpgme_sig_notation_get. + * Makefile.am (libgpgme_real_la_SOURCES): Add sig-notation.c. + * context.h (struct gpgme_context): New field sig_notations. + * gpgme.h (struct _gpgme_sig_notation): New member value_len and + critical. + (GPGME_SIG_NOTATION_CRITICAL): New symbol. + (gpgme_sig_notation_flags_t): New type. + (gpgme_sig_notation_add, gpgme_sig_notation_clear, + gpgme_sig_notation_get): New prototypes. + * ops.h (_gpgme_sig_notation_create, _gpgme_sig_notation_free): + New prototypes. + * sig-notation.c (_gpgme_sig_notation_free): New file. + * verify.c (parse_notation): Use support functions. + (release_op_data): Likewise. + * rungpg.c (append_args_from_sig_notations): New function. + (gpg_encrypt_sign, gpg_sign): Call it. + +2005-09-30 Marcus Brinkmann <marcus@g10code.de> + + * data.h (struct gpgme_data): New member file_name. + * data.c (gpgme_data_set_filename): New function. + (_gpgme_data_release): Free DH->filename if necessary. + (gpgme_data_get_filename): New function. + * rungpg.c (gpg_encrypt): Set filename option. + (gpg_encrypt_sign): Likewise. + (gpg_sign): Likewise. + * libgpgme.vers (GPGME_1.1): Add gpgme_data_set_file_name and + gpgme_data_get_file_name. + + * decrpyt.c, verify.c, gpgme.h: Replace plaintext_filename with + file_name. + +2005-09-29 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (struct _gpgme_key): Add field is_qualified. + (struct _gpgme_subkey): Likewise. + * keylist.c (set_subkey_capability, set_mainkey_capability): Set + field is_qualified. + +2005-09-23 Werner Koch <wk@g10code.com> + + * w32-io.c (_gpgme_io_pipe): Removed use of environment variable + again. + (create_reader, create_writer): Set thread priority higher. + +2005-09-19 Werner Koch <wk@g10code.com> + + * w32-io.c (_gpgme_io_pipe): New environment variable to change + the size of the pipe buffer. + +2005-09-13 Werner Koch <wk@g10code.com> + + * ath.c: Changes to make it work under W32. + +2005-09-12 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (libgpgme_la_SOURCES): Set to ath.h and ath.c. + (ath_pth_src, ath_pthread_src): Removed. + (w32_o_files): Replace ath-compat.o with ath.o. + (libgpgme_pth_la_CFLAGS): New variable. + * ath-compat.c, ath-pthread-compat.c, ath-pth-compat.c: Removed. + * ath.h (ath_pthread_available, ath_pth_available): Removed. + (ath_init) [!_ATH_EXT_SYM_PREFIX]: Do not define macro. + (struct ath_ops, ath_init) [_ATH_COMPAT]: Removed. + (_ATH_COMPAT): Macro removed. + * posix-sema.c (_gpgme_sema_subsystem_init): Do not call + _gpgme_ath_init. + +2005-09-12 Marcus Brinkmann <marcus@g10code.de> + + * keylist.c (release_op_data): Do not free opd->tmp_uid. + +2005-09-07 Werner Koch <wk@g10code.com> + + * w32-io.c (build_commandline): Quote argv[0]. + +2005-08-26 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (command_handler): Use _gpgme_io_write instead of write. + + * edit.c (command_handler): Do not depend on PROCESSED being + available. + + * engine.h (engine_command_handler_t): Add new argument processed. + * ops.h (_gpgme_passphrase_command_handler_internal): Rename + prototype to ... + (_gpgme_passphrase_command_handler): ... this one. + * passphrase.c (_gpgme_passphrase_command_handler_internal): + Rename to ... + (_gpgme_passphrase_command_handler): ... this one. + * edit.c (command_handler): Add new argument processed. Remove + local variable with the same name. Always return processed as + true. + * rungpg.c (command_handler): Send a newline character if the + handler did not. + +2005-08-26 Werner Koch <wk@g10code.com> + + * w32-util.c (read_w32_registry_string): Updated from code used by + GnuPG. This allows for expanding strings and features the + implicit fallback key. + (w32_shgetfolderpath, find_program_at_standard_place): New. + (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): With no registry + entry, locate the programs at the standard place. + (dlopen, dlsym, dlclose): New, so that we can keep on using what + we are accustomed to. + + * debug.c (debug_init): Use PATHSEP_C so that under W32 a + semicolon is used which allows us to create files with drive + letters. + + * w32-io.c (_gpgme_io_read, _gpgme_io_write): Print content in + debug mode too. + +2005-07-27 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (gpgme_status_code_t): Add GPGME_STATUS_PLAINTEXT. + (struct _gpgme_op_decrypt_result): New member plaintext_filename. + (struct _gpgme_op_verify_result): Likewise. + * ops.h (_gpgme_parse_plaintext): Add prototype. + * op-support.c (_gpgme_parse_plaintext): New function. + * decrypt.c (release_op_data): Release + OPD->result.plaintext_filename. + (_gpgme_decrypt_status_handler): Handle GPGME_STATUS_PLAINTEXT. + * verify.c (release_op_data): Release + OPD->result.plaintext_filename. + (_gpgme_verify_status_handler): Handle GPGME_STATUS_PLAINTEXT. + +2005-08-08 Werner Koch <wk@g10code.com> + + * util.h (stpcpy): Renamed to .. + (_gpgme_stpcpy): .. this and made inline. This avoids duplicate + definitions when linking statically. + * stpcpy.c: Removed. + +2005-08-19 Werner Koch <wk@g10code.com> + + * gpgme.def: New. + * versioninfo.rc.in: New. + * Makefile.am: Addes support for building a W32 DLL. + + * ttyname_r.c (ttyname_r) [W32]: Return error. + * ath-compat.c [W32]: select and co are not yet supported; return + error. + * data-stream.c (stream_seek): Use ftell if ftello is not available. + +2005-07-26 Marcus Brinkmann <marcus@g10code.de> + + * keylist.c (gpgme_get_key): Allow key IDs. + +2005-06-20 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.m4: Only call GPGME_CONFIG if found. + +2005-06-03 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (struct _gpgme_signature): New members pubkey_algo and + hash_algo. + * verify.c (parse_valid_sig): Parse pubkey and hash algo numbers. + (parse_new_sig): Parse pubkey, hash algo and timestamp for ERRSIG. + + (_gpgme_decrypt_status_handler): Fix last change. + + * gpgme.h (struct _gpgme_recipient): New structure. + (gpgme_recipient_t): New type. + (struct _gpgme_op_decrypt_result): Add member recipients. + * decrypt.c (op_data_t): New member last_recipient_p. + (_gpgme_op_decrypt_init_result): Initialize last_recipient_p. + (parse_enc_to): New function. + (_gpgme_decrypt_status_handler): Handle status ENC_TO and + NO_SECKEY. + + * wait-global.c (gpgme_wait): Break out of the fd processing loop + after an error. + Reported by Igor Belyi <gpgme@katehok.ac93.org>. + +2005-06-02 Marcus Brinkmann <marcus@g10code.de> + + * wait.h (_gpgme_run_io_cb): New prototype. + * wait.c (_gpgme_run_io_cb): New function. + * wait-global.c (gpgme_wait): Call it. + * wait-user.c (_gpgme_user_io_cb_handler): Likewise. + * wait-private.c (_gpgme_wait_on_condition): Likewise. + +2005-06-02 Werner Koch <wk@g10code.com> + + * passphrase.c (_gpgme_passphrase_status_handler): Take care of + GPGME_STATUS_NEED_PASSPHRASE_PIN. + (_gpgme_passphrase_command_handler_internal): Also act on the key + "passphrase.pin.ask". + + * gpgme.h: Added status codes GPGME_STATUS_SIG_SUBPACKET, + GPGME_STATUS_NEED_PASSPHRASE_PIN, GPGME_STATUS_SC_OP_FAILURE, + GPGME_STATUS_SC_OP_SUCCESS, GPGME_STATUS_CARDCTRL, + GPGME_STATUS_BACKUP_KEY_CREATED. + +2005-05-28 Marcus Brinkmann <marcus@g10code.de> + + * data-user.c: Include <errno.h>. + +2005-05-17 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_new): Set the CTX->include_certs default to the + default. + +2005-05-11 Marcus Brinkmann <marcus@g10code.de> + + * w32-io.c (_gpgme_io_select): Fix loop increment. + +2005-05-05 Marcus Brinkmann <marcus@g10code.de> + + * data-user.c (user_release): Only call user hook if provided. + (user_seek): Return EBADF if no user hook is provided. + (user_read): Likewise. + (user_write): Likewise. + +2005-04-28 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (GPGME_INCLUDE_CERTS_DEFAULT): New macro. + * engine-gpgsm.c (gpgsm_sign): Send the include-certs option after + the reset, just for cleanliness, and do not sent it at all if the + default is requested. + * gpgme.c (gpgme_set_include_certs): Allow to use + GPGME_INCLUDE_CERTS_DEFAULT. + +2005-04-21 Werner Koch <wk@g10code.com> + + * verify.c (calc_sig_summary): Set the key revoked bit. + +2005-04-14 Marcus Brinkmann <marcus@g10code.de> + + * wait-global.c (gpgme_wait): Use LI->ctx when checking a context + in the list, not the user-provided CTX. + Reported by Igor Belyi <gpgme@katehok.ac93.org>. + + * wait-global.c (gpgme_wait): If no context is found, and we + should not hang, set *status to 0 and return NULL. + Reported by Igor Belyi <gpgme@katehok.ac93.org>. + +2005-03-24 Marcus Brinkmann <marcus@g10code.de> + + * data.h (EOPNOTSUPP) [_WIN32]: Remove definition. + * data.c (EOPNOTSUPP) [HAVE_W32_SYSTEM]: Remove definition. + (gpgme_data_read, gpgme_data_write, gpgme_data_seek): Return + ENOSYS instead EOPNOTSUPP. + * data-compat.c (EOPNOTSUPP) [HAVE_W32_SYSTEM]: Remove definition. + (gpgme_error_to_errno): Map GPG_ERR_NOT_SUPPORTED + to ENOSYS. + +2005-03-24 Marcus Brinkmann <marcus@g10code.de> + + * io.h: Rename to ... + * priv-io.h: ... this. + * Makefile.am (libgpgme_real_la_SOURCES): Change io.h to priv-io.h. + * data.c, engine-gpgsm.c, posix-io.c, rungpg.c, version.c, + w32-io.c, wait-private.c, wait-global.c, wait-user.c, wait.c: + Change all includes of "io.h" to "priv-io.h" + +2005-03-09 Werner Koch <wk@g10code.com> + + * w32-util.c (_gpgme_get_gpg_path, _gpgme_get_gpgsm_path): Do not + cast away type checks. + + * io.h [W32]: Do not include stdio.h. If it is needed do it at + the right place. + + * data.h [W32]: Removed kludge for EOPNOTSUP. + * data.c, data-compat.c [W32]: Explicitly test for it here. + + Replaced use of _WIN32 by HAVE_W32_SYSTEM except for public header + files. + +2005-03-07 Timo Schulz <twoaday@g10code.de> + + * gpgme.h: [_WIN32] Removed ssize_t typedef. + * ath.h: [_WIN32] Added some (dummy) types. + * io.h: [_WIN32] include stdio.h. + * data.h: [_WIN32] Define EOPNOTSUPP. + * w32-io.c [_WIN32] (_gpgme_io_subsystem_init): New. + * gpgme.c [_WIN32] (gpgme_set_locale): Disabled. + +2004-12-12 Marcus Brinkmann <marcus@g10code.de> + + * engine.c (_gpgme_set_engine_info): Fix assertion. + +2004-12-11 Marcus Brinkmann <marcus@g10code.de> + + * util.h [HAVE_CONFIG_H && HAVE_TTYNAME_R] (ttyname_r): Define + prototype. + * ttyname_r.c: New file. + +2004-12-07 Marcus Brinkmann <marcus@g10code.de> + + * putc_unlocked.c, funopen.c: I just claim copyright on these + files and change their license to LGPL, because they are totally + trivial wrapper functions. + * isascii.c: Change copyright notice to the one from ctype/ctype.h + in the GNU C Library (CVS Head 2004-10-10), where isascii is + defined as a macro doing exactly the same as the function in this + file. + * memrchr.c: Update from the GNU C Library (CVS Head 2001-07-06). + * stpcpy.c: Update from the GNU C Library (CVS Head 2004-10-10). + * ath.c, ath-compat.c, ath.h, ath-pth.c, ath-pth-compat.c, + ath-pthread.c, ath-pthread-compat.c, context.h, conversion.c, + data.c, data-compat.c, data-fd.c, data.h, data-mem.c, + data-stream.c, data-user.c, debug.c, debug.h, decrypt.c, + decrypt-verify.c, delete.c, edit.c, encrypt.c, encrypt-sign.c, + engine-backend.h, engine.c, engine-gpgsm.c, engine.h, error.c, + export.c, genkey.c, get-env.c, gpgme.c, gpgme.h, import.c, io.h, + key.c, keylist.c, mkstatus, Makefile.am, ops.h, op-support.c, + passphrase.c, posix-io.c, posix-sema.c, posix-util.c, progress.c, + rungpg.c, sema.h, sign.c, signers.c, trust-item.c, trustlist.c, + util.h, verify.c, version.c, w32-io.c, w32-sema.c, w32-util.c, + wait.c, wait-global.c, wait.h, wait-private.c, wait-user.c: Change + license to LGPL. + +2004-12-07 Marcus Brinkmann <marcus@g10code.de> + + * libgpgme.vers (GPGME_1.1): New version. + * engine-backend.h (struct engine_ops): Add argument FILE_NAME to + member get_version(). Add arguments FILE_NAME and HOME_DIR to + member new(). Change return type of get_file_name and get_version + to char *. + * engine-gpgsm.c (gpgsm_get_version): Change return type to char + pointer. Do not cache result. + (gpgsm_new): Add file_name and home_dir argument, and use them + instead of the defaults, if set. + * rungpg.c (struct engine_gpg): New member file_name. + (gpg_get_version): Change return type to char pointer, and do not + cache result. + (gpg_release): Free gpg->file_name. + (gpg_new): Take new arguments file_name and home_dir. Set the + --homedir argument if HOME_DIR is not NULL. Set gpg->file_name. + (start): Use gpg->file_name instead _gpgme_get_gpg_path, if set. + * engine.h (_gpgme_engine_info_copy, _gpgme_engine_info_release): + New prototypes. + (_gpgme_engine_new): Change first argument to gpgme_engine_info_t + info. + * engine.c: Include <assert.h>. + (gpgme_get_engine_info): Set *INFO within the lock. Move + ENGINE_INFO and ENGINE_INFO_LOCK to .... + (engine_info, engine_info_lock): ... here. New static variables. + (engine_get_version): Add file_name argument to + get_version invocation. Change return type to char pointer. + (gpgme_engine_check_version): Rewritten to free() the return value + of engine_get_version after using it. + (_gpgme_engine_info_release): New function. + (gpgme_get_engine_info): Rewritten. + (_gpgme_engine_info_copy): New function. + (_gpgme_set_engine_info): New function. + (gpgme_set_engine_info): New function. + (_gpgme_engine_new): Change first argument to gpgme_engine_info_t + info, and use that. + * gpgme.h (struct _gpgme_engine_info): Change type of file_name + and version to char * (remove the const). New member home_dir. + (gpgme_set_engine_info, gpgme_ctx_get_engine_info, + gpgme_ctx_set_engine_info): New prototypes. + * context.h (struct gpgme_context): New member engine_info. + * gpgme.c (gpgme_new): Allocate CTX->engine_info. + (gpgme_release): Deallocate CTX->engine_info. + (gpgme_ctx_get_engine_info, gpgme_ctx_set_engine_info): New + functions. + * op-support.c (_gpgme_op_reset): Look for correct engine info and + pass it to _gpgme_engine_new. + * version.c (gpgme_check_version): Adjust to + _gpgme_compare_versions returning an int. + (_gpgme_compare_versions): Return an int value, not a const char + pointer. + * ops.h (_gpgme_compare_versions): Same for prototype. + +2004-10-03 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * op-support.c (_gpgme_op_data_lookup): Use char pointer for + pointer arithmetic. + +2004-09-30 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.m4: Add copyright notice. + +2004-08-18 Marcus Brinkmann <marcus@g10code.de> + + * passphrase.c (_gpgme_passphrase_status_handler): Always run the + status handler. + +2004-08-17 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (build_argv): Use --no-sk-comment, not --no-comment. + +2004-06-23 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * libgpgme.vers: Remove C-style comment, which is not supported by + older binutils. + +2004-05-21 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.m4: Quote first argument to AC_DEFUN. + +2004-04-21 Werner Koch <wk@gnupg.org> + + * key.c (gpgme_key_unref): Allow passing NULL like free does. + The rule of least surprise. + +2004-04-15 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * decrypt-verify.c (decrypt_verify_status_handler): Hack to cope + with meaningless error codes from the verify status function. + +2004-04-05 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_new): Protect _only_ tty related code with + isatty(). Submitted by Bernhard Herzog. + +2004-03-11 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme-config.in: Do not emit include and lib directory for + prefix "/usr" or "". + +2004-03-03 Werner Koch <wk@gnupg.org> + + * engine-gpgsm.c (gpgsm_export_ext): Properly insert a space + beween patterns. + +2004-02-18 Werner Koch <wk@gnupg.org> + + * gpgme-config.in: Ignore setting of --prefix. + +2004-02-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * gpgme.h: Add GPGME_KEYLIST_MODE_VALIDATE. + * engine-gpgsm.c (gpgsm_keylist): Send this to gpgsm. + +2004-02-15 Werner Koch <wk@gnupg.org> + + * memrchr.c (memrchr): Fixed implementation. Problem pointed out + by Adriaan de Groot. + +2004-02-01 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * conversion.c (_gpgme_map_gnupg_error): Handle numerical codes as + used by GnuPG 1.9.x + +2004-01-13 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (struct _gpgme_key_sig): Fix comment on REVOKED. + +2004-01-12 Werner Koch <wk@gnupg.org> + + * sign.c: Include util.h for prototype of _gpgme_parse_timestamp. + +2003-12-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * gpgme.h (_GPGME_D_CLASS): Kludge for C++ compatibility without + changing the C API. + +2003-11-19 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * keylist.c (parse_timestamp): Detect ISO 8601 timestamps and try + to convert them. + +2003-10-10 Marcus Brinkmann <marcus@g10code.de> + + * genkey.c (get_key_parameter): Make a copy of the key parameters. + Submitted by Miguel Coca <e970095@zipi.fi.upm.es>. + +2003-10-06 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme-config.in: Use $libdir, not @libdir@, for the echo + command. + + * gpgme-config.in: Rewritten. + * gpgme.m4: Rewritten. + +2003-08-19 Marcus Brinkmann <marcus@g10code.de> + + 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 <marcus@g10code.de> + + * rungpg.c (start): Use saved_errno instead errno. + +2003-08-18 Marcus Brinkmann <marcus@g10code.de> + + * funopen.c, putc_unlocked.c, isascii.c, memrchr.c: New files. + * fopencookie.c: File removed. + +2003-08-15 Marcus Brinkmann <marcus@g10code.de> + + * gpgme-config.in: Put gpg-error related flags after gpgme's. + +2003-08-14 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * verify.c (parse_new_sig): Fix status parsing case. + +2003-07-31 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (set_recipients): Move declaration of NEWLEN to + the beginning of the block. + +2003-06-22 Marcus Brinkmann <marcus@g10code.de> + + * data-mem.c (mem_write): Copy original buffer content. + +2003-06-22 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h (gpgme_user_ids_release, gpgme_user_ids_append): Remove + prototypes. + +2003-06-06 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * verify.c (parse_new_sig): Fix ERRSIG case. + Submitted by Benjamin Lee <benjaminlee@users.sf.net>. + +2003-05-18 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * keylist.c (finish_key): Clear OPD->tmp_uid. + +2003-05-18 Marcus Brinkmann <marcus@g10code.de> + + * verify.c (_gpgme_verify_status_handler): Return GPGME_No_Data + for NODATA status without signatures. + +2003-05-05 Marcus Brinkmann <marcus@g10code.de> + + * key.c (_gpgme_key_append_name): Use decoded string to parse user id. + (_gpgme_key_add_sig): Likewise. + +2003-05-04 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * edit.c (_gpgme_edit_status_handler): Call the progress status + handler. + +2003-02-05 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <Marc.Mutz@uni-bielefeld.de>. + +2003-02-04 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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-19 Marcus Brinkmann <marcus@g10code.de> + + * 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-19 Miguel Coca <mcoca@gnu.org> + + * 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-29 Marcus Brinkmann <marcus@g10code.de> + + * 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-30 Marcus Brinkmann <marcus@g10code.de> + + * 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-06 Werner Koch <wk@gnupg.org> + + * keylist.c (set_mainkey_capability): Handle 'd' and 'D' used + since gpg 1.3 to denote disabled keys. + +2003-01-06 Marcus Brinkmann <marcus@g10code.de> + + * data-mem.c: Include <string.h>. + * engine.c: Likewise. + +2003-01-06 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (libgpgme_la_DEPENDENCIES): Correct bug in last change. + +2002-12-24 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * data-mem.c (mem_release): Fix gcc warning. + * data-user.c (user_release): Likewise. + +2002-12-06 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.h [_MSC_VER]: Define ssize_t as long. + +2002-11-22 Werner Koch <wk@gnupg.org> + + * engine-gpgsm.c (_gpgme_gpgsm_new): Save the result of a first + setlocale before doing another setlocale. + +2002-11-21 Marcus Brinkmann <marcus@g10code.de> + + * decrypt.c: Some beautyfication. + + * verify.c (_gpgme_verify_status_handler): Treat + GPGME_STATUS_UNEXPECTED like GPGME_STATUS_NODATA. + Reported by Miguel Coca <e970095@zipi.fi.upm.es>. + +2002-11-19 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * rungpg.c (gpg_keylist): Add --with-fingerprint to gpg invocation + twice, to get fingerprints on subkeys. Suggested by Timo Schulz + <twoaday@freakmail.de>. + (gpg_keylist_ext): Likewise. + +2002-11-05 Marcus Brinkmann <marcus@g10code.de> + + * 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 <e970095@zipi.fi.upm.es>. + +2002-10-10 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_verify) [!ENABLE_GPGSM]: Add + missing argument. + +2002-10-09 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * ath.c: Include sys/time.h if sys/select.h is not available. + +2002-09-13 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * Makefile.am (assuan_libobjs): Use @LTLIBOBJS@ instead @LIBOBJS@. + +2002-09-02 Marcus Brinkmann <marcus@g10code.de> + + * debug.c (_gpgme_debug_add): Test *LINE, not LINE. + (_gpgme_debug_end): Likewise. + Reported by Dr. Stefan Dalibor <Dr.Stefan.Dalibor@bfa.de>. + +2002-09-02 Marcus Brinkmann <marcus@g10code.de> + + * 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 <Dr.Stefan.Dalibor@bfa.de>. + +2002-09-02 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * rungpg.c (_gpgme_gpg_op_edit): Add args from signers. + Suggested by Miguel Coca <e970095@zipi.fi.upm.es>. + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * passphrase.c (_gpgme_passphrase_status_handler): Reset + CTX->result.passphrase->no_passphrase if passphrase is given (good + or bad). Submitted by Jean DIRAISON <jean.diraison@free.fr>. + +2002-08-28 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * gpgme-config.in: Made --prefix work for --libs. + +2002-08-21 Marcus Brinkmann <marcus@g10code.de> + + * ath.h: Update list of symbols that get a prefix: Rename the + ath_mutex_*_available symbols to ath_*_available. + +2002-08-21 Marcus Brinkmann <marcus@g10code.de> + + * stpcpy.c: New file from gnulib. + * Makefile.am (assuan_libobjs): Remove jnlib. + +2002-08-20 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * rungpg.c (_gpgme_gpg_op_edit): Use --with-colons. + +2002-07-28 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * delete.c (delete_problem): New case ambigious specification. + (delete_status_handler): Handle new case (poorly). + +2002-07-25 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_delete): Implement this. + +2002-07-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * keylist.c (gpgme_op_keylist_ext_start): Always use our own FD + table (eg use synchronous mode). + +2002-06-27 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h: Fix documentation of key attribute retrieval functions. + +2002-06-28 Marcus Brinkmann <marcus@g10code.de> + + * 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-26 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * engine-gpgsm.c (_gpgme_gpgsm_set_io_cbs) [ENABLE_GPGSM]: Fixed + function arguments. + +2002-06-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_export): Implement. + +2002-06-21 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * wait.c (_gpgme_remove_io_cb): Unlock FDT->lock. + +2002-06-20 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * verify.c (gpgme_op_verify): Make sure that we never access an + unitialized result structure. + +2002-06-12 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_start): Move the code that sets the + close notification for the status fd to ... + (_gpgme_gpgsm_new): ... here. + * wait.h: Include "sema.h". Remove prototypes of + _gpgme_remove_proc_from_wait_queue and + _gpgme_register_pipe_handler. Add prototypes of + _gpgme_fd_table_init, _gpgme_fd_table_deinit, _gpgme_fd_table_put, + _gpgme_add_io_cb, _gpgme_remove_io_cb, _gpgme_wait_event_cb and + _gpgme_wait_one.. + * wait.c: Remove global variables PROC_QUEUE, PROC_QUEUE_LOCK, + FD_TABLE_SIZE, FD_TABLE, FD_TABLE_LOCK. New global variables + FDT_GLOBAL, CTX_DONE_LIST, CTX_DONE_LIST_SIZE, + CTX_DONE_LIST_LENGTH and CTX_DONE_LIST_LOCK. Remove struct + proc_s. Replace struct wait_item_s. + (_gpgme_fd_table_init): New function. + (_gpgme_fd_table_deinit): Likewise. + (_gpgme_fd_table_put): Likewise. + (set_process_done): Remove function. + (do_select): Take argument FDT. Use that to decide which fds to + select on. + (_gpgme_remove_proc_from_wait_queue): Remove function. + (_gpgme_wait_event_cb): New function. + (_gpgme_wait_one): Likewise. + (_gpgme_register_pipe_hanldler): Remove function. + (_gpgme_add_io_cb): New function. + (_gpgme_remove_io_cb): Likewise. + (_gpgme_freeze_fd): Remove function. + (_gpgme_thaw_fd): Remove function. + * rungpg.c (struct fd_data_map_s): Add new member TAG. + (struct gpg_object_s): Likewise for STATUS and COLON. Add member + IDX to CMD. Add new member IO_CBS. + (close_notify_handler): New variables POSSIBLY_DONE and NOT_DONE. + For each I/O callback, check if it should be unregistered. If all + callbacks have been unregistered, trigger GPGME_EVENT_DONE. + Remove member RUNNING. + (_gpgme_gpg_new): Initialize new members. + (_gpgme_gpg_release): Check PID not RUNNING. Don't call + _gpgme_remove_proc_from_wait_queue. Close GPG->CMD.FD if set. + (build_argv): Store away the index instead the file descriptor for + CMD. + (_gpgme_gpg_add_io_cb): New function. + (_gpgme_gpg_spawn): Use _gpgme_gpg_add_io_cb to register IO + callbacks. + (gpg_status_handler): Change return type to void, remove PID + argument, close filedescriptor if EOF or error occurs. + (read_status): Use _gpgme_gpg_add_io_cb instead _gpgme_thaw_fd. + Use IO_CBS->remove instead _gpgme_freeze_fd. + (gpg_colon_line_handler): Change return type to void, remove PID + argument, close filedescriptor if EOF or error occurs. + (command_cb): Use IO_CBS->remove instead _gpgme_freeze_fd. + (_gpgme_gpg_set_io_cbs): New function. + * rungpg.h (_gpgme_gpg_set_io_cbs): Prototype for + _gpgme_gpg_set_io_cbs. + * gpgme.h (GpgmeIOCb): New type. + (GpgmeRegisterIOCb): Likewise. + (GpgmeRemoveIOCb): Likewise. + (GpgmeEventIO): Likewise. + (GpgmeEventIOCb): Likewise. + (struct GpgmeIOCbs): New structure to hold I/O callbacks. + (gpgme_set_op_io_cbs): New prototype. + (gpgme_get_op_io_cbs): Likewise. + * ops.h: New prototype for _gpgme_op_event_cb. Remove prototypes + for _gpgme_freeze_fd and _gpgme_thaw_fd. Remove PID argument from + _gpgme_data_inbound_handler and _gpgme_data_outbound_handler + prototype. Add prototype for _gpgme_op_reset. + Add synchronous argument to _gpgme_decrypt_start prototype. + * io.h: Beautification. + * gpgme.c: Include "wait.h". + (gpgme_new): Initialize FDT. + (gpgme_set_io_cbs): New function. + (gpgme_get_io_cbs): Likewise. + (_gpgme_op_event_cb): Likewise. + * data.c (_gpgme_data_inbound_handler): Change return type to + void. Drop PID argument. Close FD on error and EOF. + (write_mem_data): Don't close FD here ... + (write_cb_data): ... or here ... + (_gpgme_data_outbound_handler): ... but here. Change return type + to void. Drop PID argument. + * context.h: Include "wait.h". + (struct gpgme_context_s): New members FDT and IO_CBS. + * op-support.c: New file. + * Makefile.am (libgpgme_la_SOURCES): Add op-support.c. + * ops.h: Add prototype for _gpgme_op_reset(). + * decrypt.c (_gpgme_decrypt_start): New argument SYNCHRONOUS. Use + _gpgme_op_reset. + (gpgme_op_decrypt_start): Add synchronous argument. + (gpgme_op_decrypt): Likewise. Use _gpgme_wait_one instead + gpgme_wait. + * delete.c (gpgme_op_delete_start): Rename to ... + (_gpgme_op_delete_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_delete_start): Just a wrapper around + _gpgme_op_delete_start now. + (gpgme_op_delete): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * encrypt.c: Include "wait.h". + (ggpgme_op_encrypt_start): Rename to ... + (_gpgme_op_encrypt_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_encrypt_start): Just a wrapper around + _gpgme_op_encrypt_start now. + (gpgme_op_encrypt): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * encrypt_sign.c (gpgme_op_encrypt_sign_start): Rename to ... + (_gpgme_op_encrypt_sign_start): ... this. New argument + SYNCHRONOUS. Use _gpgme_op_reset. Make function static. + (gpgme_op_encrypt_sign_start): Just a wrapper around + _gpgme_op_encrypt_sign_start now. + (gpgme_op_encrypt_sign): Add synchronous argument. Use + _gpgme_wait_one instead gpgme_wait. + * export.c (gpgme_op_export_start): Rename to ... + (_gpgme_op_export_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_export_start): Just a wrapper around + _gpgme_op_export_start now. + (gpgme_op_export): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * genkey.c (gpgme_op_genkey_start): Rename to ... + (_gpgme_op_genkey_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_genkey_start): Just a wrapper around + _gpgme_op_genkey_start now. + (gpgme_op_genkey): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * import.c (gpgme_op_import_start): Rename to ... + (_gpgme_op_import_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_import_start): Just a wrapper around + _gpgme_op_import_start now. + (gpgme_op_import): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * keylist.c (gpgme_op_keylist_start): Use _gpgme_op_reset. + (gpgme_op_keylist_ext_start): Likewise. + * sign.c (gpgme_op_sign_start): Rename to ... + (_gpgme_op_sign_start): ... this. New argument SYNCHRONOUS. Use + _gpgme_op_reset. Make function static. + (gpgme_op_sign_start): Just a wrapper around _gpgme_op_sign_start + now. + (gpgme_op_sign): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * trustlist.c (gpgme_op_trustlist_start): Use _gpgme_op_reset. + * verify.c (gpgme_op_verify_start): Rename to ... + (_gpgme_op_verify_start): ... this. New argument SYNCHRONOUS. + Use _gpgme_op_reset. Make function static. + (gpgme_op_verify_start): Just a wrapper around + _gpgme_op_verify_start now. + (gpgme_op_verify): Add synchronous argument. Use _gpgme_wait_one + instead gpgme_wait. + * engine-gpgsm.c (iocb_data_t): New type. + (struct gpgsm_object_s): New member status_cb. Replace input_fd + and input_data with input_cb. Replace output_fd and output_data + with output_cb. Replace message_fd and message_data with + message_cb. New member io_cbs. + (_gpgme_gpgsm_new): Initialize all new members (and drop the old + ones). + (close_notify_handler): New variable POSSIBLY_DONE. For each I/O + callback, check if it should be unregistered. If all callbacks + have been unregistered, trigger GPGME_EVENT_DONE. + (_gpgme_gpgsm_release): Remove variable PID. Use new variable + names to close the file descriptors. + (_gpgme_gpgsm_op_decrypt): Use new variable names, + (_gpgme_gpgsm_op_encrypt): Likewise. + (_gpgme_gpgsm_op_genkey): Likewise. + (_gpgme_gpgsm_op_import): Likewise. + (_gpgme_gpgsm_op_keylist): Likewise. + (_gpgme_gpgsm_op_keylist_ext): Likewise. + (_gpgme_gpgsm_op_sign): Likewise. + (_gpgme_gpgsm_op_verify): Likewise. + (gpgsm_status_handler): Drop argument PID. Change return type to + void. Close status pipe before returning because of EOF or error. + (_gpgme_gpgsm_add_io_cb): New function. + (_gpgme_gpgsm_start): Use _gpgme_gpgsm_add_io_cb to register + callback function. + (_gpgme_gpgsm_set_io_cbs): New function. + * engine-gpgsm.h: New prototype for _gpgme_gpgsm_set_io_cbs. + * engine.c (_gpgme_engine_set_io_cbs): New function. + * engine.h: New prototype for _gpgme_engine_set_io_cbs. + +2002-06-04 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (libgpgme_la_SOURCES): Remove mutex.h. + +2002-06-03 Marcus Brinkmann <marcus@g10code.de> + + * key.c: Include <ctype.h>. + (_gpgme_key_append_name): Skip one more char when + processing escaped char. Submitted by Marc Mutz <mutz@kde.org>. + Handle hexadecimal encodings. Also reported by Marc. Thanks! + +2002-06-02 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext): Aehmm, added + missing variable definition. Oohh - Marcus was faster. + +2002-05-22 Marcus Brinkmann <marcus@gnu.org> + + * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext): Fix last change. + +2002-05-21 Werner Koch <wk@gnupg.org> + + * engine-gpgsm.c (_gpgme_gpgsm_op_keylist) + (_gpgme_gpgsm_op_keylist_ext): Pass the keylist mode to gpgsm. + +2002-05-10 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * Makefile.am (libgpgme_la_LIBADD): Use libtool libraries. + +2002-04-25 Marcus Brinkmann <marcus@g10code.de> + + * rungpg.c (_gpgme_gpg_release): Call gpgme_data_release on + GPG->cmd.cb_data, not xfree. + +2002-04-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (map_assuan_error): Add new error codes. + +2002-04-23 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * gpgme.c (gpgme_get_progress_cb): Allow either return parameter + to be NULL. + (gpgme_get_passphrase_cb): Likewise. + +2002-04-22 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * Makefile.am (libgpgme_la_SOURCES): Add mutex.h + +2002-03-21 Werner Koch <wk@gnupg.org> + + * util.h [!HAVE_FOPENCOOKIE]: Make sure off_t and ssize_t are + defined. + +2002-03-18 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * util.h [!HAVE_FOPENCOOKIE]: Fixed type. Thanks to Frank Heckenbach. + +2002-03-07 Werner Koch <wk@gnupg.org> + + * gpgme.h (gpgme_op_keylist_ext_start): Add prototype. + +2002-03-06 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * passphrase.c (_gpgme_passphrase_status_handler): Also set the + error No_Passphrase if only a bad passphrase was provided. + +2002-03-03 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_keylist_ext) [!ENABLE_GPGSM]: + Add stub function. + +2002-02-28 Werner Koch <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * verify.c (_gpgme_verify_status_handler): Fix the last change. + +2002-02-25 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * keylist.c (gpgme_op_keylist_start): Do not use a verbose listing. + +2002-02-13 Werner Koch <wk@gnupg.org> + + * vasprintf.c, fopencookie.c: Add replacement functions. + * util.h: Add prototypes for them. + +2002-02-09 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_assuan_simple_command): Return 0 if we + reach the end of the function. + +2002-02-09 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * rungpg.c (_gpgme_gpg_op_keylist): Remove handling of keylist + mode (for now). + +2002-02-06 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + 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 <marcus@g10code.de> + + * Makefile.am (MOSTLYCLEANFILES): New variable. + +2002-02-01 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_status_handler): At error, terminate the + connection to the server. + +2002-01-31 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.h: Add lots of comment and fix the formatting. Add + gpgme_trustlist_end prototype. + +2002-01-29 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.h (GpgmePassphraseCb): Change type of R_HD from void* to + void**. + +2002-01-22 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * export.c: Cleanup. + +2002-01-15 Marcus Brinkmann <marcus@g10code.de> + + * trustlist.c: Various source clean ups. + (my_isdigit): Removed. + (gpgme_op_trustlist_end): New function. + +2002-01-13 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_new): Replace General_Error with + Pipe_Error where appropriate. + +2001-12-19 Marcus Brinkmann <marcus@g10code.de> + + * engine.c: Include `string.h'. Reported by Stéphane Corthésy. + + * version.c (get_engine_info): Remove prototype. + +2001-12-19 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_set_colon_line_handler): New + function [!ENABLE_GPGSM]. + +2001-12-14 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c: Revert last change. + +2001-12-14 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (gpgsm_status_handler): Make it work with current + version of assuan. + +2001-12-05 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * keylist.c (gpgme_op_keylist_next): Set pending to 0 if EOF + occurs. + +2001-11-26 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Fix stupid typo. + +2001-11-24 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_sign): Implement it according to + the current protocol definition. + +2001-11-23 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_new): Set CLOEXEC flag for parent + ends of the pipe. + +2001-11-22 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * gpgme.h (gpgme_set_protocol): New prototype. + +2001-11-22 Marcus Brinkmann <marcus@g10code.de> + + * engine-gpgsm.c (_gpgme_gpgsm_op_decrypt): New function. + (_gpgme_gpgsm_op_import): Likewise. + +2001-11-22 Marcus Brinkmann <marcus@g10code.de> + + * 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 <wk@gnupg.org> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * Makefile.am (libgpgme_la_INCLUDES): Remove obsolete directive. + (AM_CPPFLAGS): New directive [BUILD_ASSUAN]. + (libgpgme_la_LIBADD): Likewise. + +2001-11-20 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * decrypt.c (command_handler): Fix last change. + +2001-11-15 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * rungpg.c (_gpgme_gpg_release): Release GPG->cmd.cb_data. + Release all members of the list GPG->arglist. + Reported by Michael Schmidt <mschmidt@cs.uni-sb.de>. + +2001-11-02 Marcus Brinkmann <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * 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 <marcus@g10code.de> + + * data.c (_gpgme_data_append): Check if LENGTH is smaller than + ALLOC_CHUNK, not DH->length. + +2001-10-17 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.c (gpgme_set_protocol): Fix last change. + +2001-10-15 Werner Koch <wk@gnupg.org> + + * gpgme.h (GpgmeProtocol): New. + * gpgme.c (gpgme_set_protocol): New. + +2001-09-26 Werner Koch <wk@gnupg.org> + + * gpgme.c (gpgme_set_passphrase_cb): Ignore a NULL context. + (gpgme_set_progress_cb): Ditto. Suggested by Mark Mutz. + +2001-09-17 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * data.c (gpgme_data_rewind): Allow rewind for callbacks. + +2001-09-07 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * encrypt.c (gpgme_op_encrypt): Hack to detect no valid recipients. + +2001-07-30 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * data.c (gpgme_data_read): Add a a way to return the available bytes. + +2001-07-23 Werner Koch <wk@gnupg.org> + + * util.c: Removed stpcpy() because we use the version from jnlib. + +2001-07-19 Werner Koch <wk@gnupg.org> + + * mkstatus: Define the collating sequence for sort. + +2001-06-26 Werner Koch <wk@gnupg.org> + + * rungpg.h: Add STATUS_UNEXPECTED as suggested by Timo. + +2001-06-15 Werner Koch <wk@gnupg.org> + + * keylist.c (set_userid_flags): Fixed the assigned values. Kudos + to Timo for pointing this out. + +2001-06-01 Werner Koch <wk@gnupg.org> + + * debug.c (_gpgme_debug_begin): Fixed a /tmp race. Noted by + Johannes Poehlmann. + +2001-05-28 Werner Koch <wk@gnupg.org> + + * 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 <jose@jaimedelamo.eu.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * keylist.c (parse_timestamp): Adjusted for the changed + --fixed-list-mode of gpg 1.0.4h. + +2001-04-05 Werner Koch <wk@gnupg.org> + + * verify.c (gpgme_op_verify_start): Enabled pipemode for detached sigs. + +2001-04-04 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * w32-io.c (destroy_reader,destroy_writer): Fixed syntax error. + Thanks to Jan Oliver Wagner. + +2001-03-13 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * 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 should 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 <wk@gnupg.org> + + * data.c (_gpgme_data_release_and_return_string): Fixed string + termination. + +2001-01-22 Werner Koch <wk@gnupg.org> + + * 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 <wk@gnupg.org> + + * data.c (gpgme_data_rewind): Allow to rewind data_type_none. + + + Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010, + 2011 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/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ea8e70e --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,230 @@ +# Copyright (C) 2000 Werner Koch (dd9jn) +# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 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, see <http://www.gnu.org/licenses/>. + +## Process this file with automake to produce Makefile.in + +# Note: moc_kdpipeiodevice should actually be a dependcy below. +EXTRA_DIST = gpgme-config.in gpgme.m4 libgpgme.vers ChangeLog-2011 \ + gpgme.h.in versioninfo.rc.in gpgme.def moc_kdpipeiodevice.cpp + +bin_SCRIPTS = gpgme-config +m4datadir = $(datadir)/aclocal +m4data_DATA = gpgme.m4 +nodist_include_HEADERS = gpgme.h + +if HAVE_PTHREAD +ltlib_gpgme_pthread = libgpgme-pthread.la +else +ltlib_gpgme_pthread = +endif + +if BUILD_W32_GLIB +ltlib_gpgme_glib = libgpgme-glib.la +else +ltlib_gpgme_glib = +endif + +if BUILD_W32_QT +ltlib_gpgme_qt = libgpgme-qt.la +else +ltlib_gpgme_qt = +endif + +lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \ + $(ltlib_gpgme_pthread) + +if HAVE_LD_VERSION_SCRIPT +libgpgme_version_script_cmd = -Wl,--version-script=$(srcdir)/libgpgme.vers +else +libgpgme_version_script_cmd = +endif + +if HAVE_DOSISH_SYSTEM +system_components = w32-util.c w32-sema.c +system_components_not_extra = w32-io.c +else +system_components = ath.h posix-util.c posix-sema.c posix-io.c +system_components_not_extra = +endif + +if HAVE_W32CE_SYSTEM +system_components += w32-ce.h w32-ce.c +endif + +if HAVE_GPGSM +gpgsm_components = engine-gpgsm.c +else +gpgsm_components = +endif + +if HAVE_ASSUAN +assuan_components = assuan-support.c engine-assuan.c +else +assuan_components = +endif + +if HAVE_GPGCONF +gpgconf_components = engine-gpgconf.c +else +gpgconf_components = +endif + +if HAVE_G13 +g13_components = engine-g13.c +else +g13_components = +endif + +if HAVE_UISERVER +uiserver_components = engine-uiserver.c +else +uiserver_components = +endif + +# These are the source files common to all library versions. We used +# to build a non-installed library for that, but that does not work +# correctly on all platforms (in particular, one can not specify the +# right linking order with libtool, as the non-installed version has +# unresolved symbols to the thread module. +main_sources = \ + 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 sig-notation.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 getauditlog.c \ + opassuan.c passwd.c \ + engine.h engine-backend.h engine.c engine-gpg.c status-table.c \ + $(gpgsm_components) $(assuan_components) $(gpgconf_components) \ + $(uiserver_components) \ + $(g13_components) vfs-mount.c vfs-create.c \ + gpgconf.c \ + sema.h priv-io.h $(system_components) dirinfo.c \ + debug.c debug.h gpgme.c version.c error.c + +libgpgme_la_SOURCES = $(main_sources) \ + ath.h ath.c $(system_components_not_extra) +libgpgme_pthread_la_SOURCES = $(main_sources) \ + ath.h ath-pthread.c $(system_components_not_extra) + +if BUILD_W32_GLIB +libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c +endif + +if BUILD_W32_QT +libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \ + kdpipeiodevice.h kdpipeiodevice.cpp kdpipeiodevice.moc +# FIXME: Add extra depedency: moc_kdpipeiodevice.cpp + +# These are built sources (normally). +# moc_kdpipeiodevice.cpp: kdpipeiodevice.h +# $(MOC4) -o $@ $< +# +# kdpipeiodevice.moc: kdpipeiodevice.cpp +# $(MOC4) -o $@ $< +endif + +# We use a global CFLAGS and CPPFLAGS setting for all library +# versions, because then every object file is only compiled once. +AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@ +AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@ + +if HAVE_W32_SYSTEM +# Windows provides us with an endless stream of Tough Love. To spawn +# processes with a controlled set of inherited handles, we need a +# wrapper process. +# Except on Windows CE. There nothing is inheritable anyway. +if HAVE_W32CE_SYSTEM +libexec_PROGRAMS = +else +libexec_PROGRAMS = gpgme-w32spawn +endif + +RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) +LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE) + +SUFFIXES = .rc .lo + +.rc.lo: + $(LTRCCOMPILE) -i "$<" -o "$@" + +gpgme_res = versioninfo.lo +no_undefined = -no-undefined +export_symbols = -export-symbols $(srcdir)/gpgme.def + +install-def-file: + $(INSTALL) $(srcdir)/gpgme.def $(DESTDIR)$(libdir)/gpgme.def + +uninstall-def-file: + -rm $(DESTDIR)$(libdir)/gpgme.def + +gpgme_deps = $(gpgme_res) gpgme.def + +else +gpgme_res = +no_undefined = +export_symbols = +install-def-file: +uninstall-def-file: + +gpgme_deps = +endif + +libgpgme_la_LDFLAGS = $(no_undefined) $(export_symbols) \ + $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) +libgpgme_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + @GPG_ERROR_LIBS@ + +libgpgme_pthread_la_LDFLAGS = $(no_undefined) $(export_symbols) \ + $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_pthread_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers +libgpgme_pthread_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + -lpthread @GPG_ERROR_LIBS@ + +if BUILD_W32_GLIB +libgpgme_glib_la_LDFLAGS = $(no_undefined) \ + $(export_symbols) $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_glib_la_DEPENDENCIES = @LTLIBOBJS@ \ + $(srcdir)/libgpgme.vers $(gpgme_deps) +libgpgme_glib_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + @GPG_ERROR_LIBS@ @GLIB_LIBS@ +endif + +if BUILD_W32_QT +libgpgme_qt_la_LDFLAGS = $(no_undefined) \ + $(export_symbols) $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ +libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) +libgpgme_qt_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + @GPG_ERROR_LIBS@ @QT4_CORE_LIBS@ +endif + +noinst_PROGRAMS = gpgme-tool +gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@ + +install-data-local: install-def-file + +uninstall-local: uninstall-def-file diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..5766ab7 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,1113 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program 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. + +@SET_MAKE@ + +# Copyright (C) 2000 Werner Koch (dd9jn) +# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 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, see <http://www.gnu.org/licenses/>. + + + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@HAVE_W32CE_SYSTEM_TRUE@am__append_1 = w32-ce.h w32-ce.c +@HAVE_W32CE_SYSTEM_FALSE@@HAVE_W32_SYSTEM_TRUE@libexec_PROGRAMS = gpgme-w32spawn$(EXEEXT) +noinst_PROGRAMS = gpgme-tool$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/gpgme-config.in $(srcdir)/gpgme.h.in \ + $(srcdir)/versioninfo.rc.in funopen.c setenv.c stpcpy.c \ + ttyname_r.c vasprintf.c +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \ + $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnupg-ttyname.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = versioninfo.rc gpgme.h gpgme-config +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libexecdir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(m4datadir)" \ + "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +@HAVE_W32_SYSTEM_TRUE@am__DEPENDENCIES_1 = versioninfo.lo +am__libgpgme_glib_la_SOURCES_DIST = 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 sig-notation.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 getauditlog.c opassuan.c passwd.c engine.h \ + engine-backend.h engine.c engine-gpg.c status-table.c \ + engine-gpgsm.c assuan-support.c engine-assuan.c \ + engine-gpgconf.c engine-uiserver.c engine-g13.c vfs-mount.c \ + vfs-create.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \ + posix-sema.c posix-io.c w32-ce.h w32-ce.c w32-util.c \ + w32-sema.c dirinfo.c debug.c debug.h gpgme.c version.c error.c \ + ath.c w32-glib-io.c +@HAVE_GPGSM_TRUE@am__objects_1 = engine-gpgsm.lo +@HAVE_ASSUAN_TRUE@am__objects_2 = assuan-support.lo engine-assuan.lo +@HAVE_GPGCONF_TRUE@am__objects_3 = engine-gpgconf.lo +@HAVE_UISERVER_TRUE@am__objects_4 = engine-uiserver.lo +@HAVE_G13_TRUE@am__objects_5 = engine-g13.lo +@HAVE_W32CE_SYSTEM_TRUE@am__objects_6 = w32-ce.lo +@HAVE_DOSISH_SYSTEM_FALSE@am__objects_7 = posix-util.lo posix-sema.lo \ +@HAVE_DOSISH_SYSTEM_FALSE@ posix-io.lo $(am__objects_6) +@HAVE_DOSISH_SYSTEM_TRUE@am__objects_7 = w32-util.lo w32-sema.lo \ +@HAVE_DOSISH_SYSTEM_TRUE@ $(am__objects_6) +am__objects_8 = conversion.lo get-env.lo data.lo data-fd.lo \ + data-stream.lo data-mem.lo data-user.lo data-compat.lo \ + signers.lo sig-notation.lo wait.lo wait-global.lo \ + wait-private.lo wait-user.lo op-support.lo encrypt.lo \ + encrypt-sign.lo decrypt.lo decrypt-verify.lo verify.lo sign.lo \ + passphrase.lo progress.lo key.lo keylist.lo trust-item.lo \ + trustlist.lo import.lo export.lo genkey.lo delete.lo edit.lo \ + getauditlog.lo opassuan.lo passwd.lo engine.lo engine-gpg.lo \ + status-table.lo $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) $(am__objects_4) $(am__objects_5) \ + vfs-mount.lo vfs-create.lo gpgconf.lo $(am__objects_7) \ + dirinfo.lo debug.lo gpgme.lo version.lo error.lo +@BUILD_W32_GLIB_TRUE@am_libgpgme_glib_la_OBJECTS = $(am__objects_8) \ +@BUILD_W32_GLIB_TRUE@ ath.lo w32-glib-io.lo +libgpgme_glib_la_OBJECTS = $(am_libgpgme_glib_la_OBJECTS) +libgpgme_glib_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgpgme_glib_la_LDFLAGS) $(LDFLAGS) -o $@ +@BUILD_W32_GLIB_TRUE@am_libgpgme_glib_la_rpath = -rpath $(libdir) +am__libgpgme_pthread_la_SOURCES_DIST = 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 sig-notation.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 getauditlog.c opassuan.c passwd.c engine.h \ + engine-backend.h engine.c engine-gpg.c status-table.c \ + engine-gpgsm.c assuan-support.c engine-assuan.c \ + engine-gpgconf.c engine-uiserver.c engine-g13.c vfs-mount.c \ + vfs-create.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \ + posix-sema.c posix-io.c w32-ce.h w32-ce.c w32-util.c \ + w32-sema.c dirinfo.c debug.c debug.h gpgme.c version.c error.c \ + ath-pthread.c w32-io.c +@HAVE_DOSISH_SYSTEM_TRUE@am__objects_9 = w32-io.lo +am_libgpgme_pthread_la_OBJECTS = $(am__objects_8) ath-pthread.lo \ + $(am__objects_9) +libgpgme_pthread_la_OBJECTS = $(am_libgpgme_pthread_la_OBJECTS) +libgpgme_pthread_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgpgme_pthread_la_LDFLAGS) $(LDFLAGS) -o $@ +@HAVE_PTHREAD_TRUE@am_libgpgme_pthread_la_rpath = -rpath $(libdir) +am__libgpgme_qt_la_SOURCES_DIST = 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 sig-notation.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 getauditlog.c opassuan.c passwd.c engine.h \ + engine-backend.h engine.c engine-gpg.c status-table.c \ + engine-gpgsm.c assuan-support.c engine-assuan.c \ + engine-gpgconf.c engine-uiserver.c engine-g13.c vfs-mount.c \ + vfs-create.c gpgconf.c sema.h priv-io.h ath.h posix-util.c \ + posix-sema.c posix-io.c w32-ce.h w32-ce.c w32-util.c \ + w32-sema.c dirinfo.c debug.c debug.h gpgme.c version.c error.c \ + ath.c w32-qt-io.cpp kdpipeiodevice.h kdpipeiodevice.cpp \ + kdpipeiodevice.moc +@BUILD_W32_QT_TRUE@am_libgpgme_qt_la_OBJECTS = $(am__objects_8) ath.lo \ +@BUILD_W32_QT_TRUE@ w32-qt-io.lo kdpipeiodevice.lo +libgpgme_qt_la_OBJECTS = $(am_libgpgme_qt_la_OBJECTS) +libgpgme_qt_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libgpgme_qt_la_LDFLAGS) $(LDFLAGS) -o $@ +@BUILD_W32_QT_TRUE@am_libgpgme_qt_la_rpath = -rpath $(libdir) +am__libgpgme_la_SOURCES_DIST = 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 sig-notation.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 \ + getauditlog.c opassuan.c passwd.c engine.h engine-backend.h \ + engine.c engine-gpg.c status-table.c engine-gpgsm.c \ + assuan-support.c engine-assuan.c engine-gpgconf.c \ + engine-uiserver.c engine-g13.c vfs-mount.c vfs-create.c \ + gpgconf.c sema.h priv-io.h ath.h posix-util.c posix-sema.c \ + posix-io.c w32-ce.h w32-ce.c w32-util.c w32-sema.c dirinfo.c \ + debug.c debug.h gpgme.c version.c error.c ath.c w32-io.c +am_libgpgme_la_OBJECTS = $(am__objects_8) ath.lo $(am__objects_9) +libgpgme_la_OBJECTS = $(am_libgpgme_la_OBJECTS) +libgpgme_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libgpgme_la_LDFLAGS) $(LDFLAGS) -o $@ +PROGRAMS = $(libexec_PROGRAMS) $(noinst_PROGRAMS) +gpgme_tool_SOURCES = gpgme-tool.c +gpgme_tool_OBJECTS = gpgme-tool.$(OBJEXT) +gpgme_tool_DEPENDENCIES = libgpgme.la +gpgme_w32spawn_SOURCES = gpgme-w32spawn.c +gpgme_w32spawn_OBJECTS = gpgme-w32spawn.$(OBJEXT) +gpgme_w32spawn_LDADD = $(LDADD) +SCRIPTS = $(bin_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libgpgme_glib_la_SOURCES) $(libgpgme_pthread_la_SOURCES) \ + $(libgpgme_qt_la_SOURCES) $(libgpgme_la_SOURCES) gpgme-tool.c \ + gpgme-w32spawn.c +DIST_SOURCES = $(am__libgpgme_glib_la_SOURCES_DIST) \ + $(am__libgpgme_pthread_la_SOURCES_DIST) \ + $(am__libgpgme_qt_la_SOURCES_DIST) \ + $(am__libgpgme_la_SOURCES_DIST) gpgme-tool.c gpgme-w32spawn.c +DATA = $(m4data_DATA) +HEADERS = $(nodist_include_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_NUMBER = @BUILD_NUMBER@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +G13 = @G13@ +GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@ +GLIBC21 = @GLIBC21@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GOBJECT_QUERY = @GOBJECT_QUERY@ +GPG = @GPG@ +GPGCONF = @GPGCONF@ +GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@ +GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@ +GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@ +GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@ +GPGSM = @GPGSM@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_PATH = @GPG_PATH@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@ +LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@ +LIBASSUAN_LIBS = @LIBASSUAN_LIBS@ +LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@ +LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@ +LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +QT4_CORE_CFLAGS = @QT4_CORE_CFLAGS@ +QT4_CORE_LIBS = @QT4_CORE_LIBS@ +RANLIB = @RANLIB@ +RC = @RC@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +emacs_local_vars_begin = @emacs_local_vars_begin@ +emacs_local_vars_end = @emacs_local_vars_end@ +emacs_local_vars_read_only = @emacs_local_vars_read_only@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Note: moc_kdpipeiodevice should actually be a dependcy below. +EXTRA_DIST = gpgme-config.in gpgme.m4 libgpgme.vers ChangeLog-2011 \ + gpgme.h.in versioninfo.rc.in gpgme.def moc_kdpipeiodevice.cpp + +bin_SCRIPTS = gpgme-config +m4datadir = $(datadir)/aclocal +m4data_DATA = gpgme.m4 +nodist_include_HEADERS = gpgme.h +@HAVE_PTHREAD_FALSE@ltlib_gpgme_pthread = +@HAVE_PTHREAD_TRUE@ltlib_gpgme_pthread = libgpgme-pthread.la +@BUILD_W32_GLIB_FALSE@ltlib_gpgme_glib = +@BUILD_W32_GLIB_TRUE@ltlib_gpgme_glib = libgpgme-glib.la +@BUILD_W32_QT_FALSE@ltlib_gpgme_qt = +@BUILD_W32_QT_TRUE@ltlib_gpgme_qt = libgpgme-qt.la +lib_LTLIBRARIES = libgpgme.la $(ltlib_gpgme_glib) $(ltlib_gpgme_qt) \ + $(ltlib_gpgme_pthread) + +@HAVE_LD_VERSION_SCRIPT_FALSE@libgpgme_version_script_cmd = +@HAVE_LD_VERSION_SCRIPT_TRUE@libgpgme_version_script_cmd = -Wl,--version-script=$(srcdir)/libgpgme.vers +@HAVE_DOSISH_SYSTEM_FALSE@system_components = ath.h posix-util.c \ +@HAVE_DOSISH_SYSTEM_FALSE@ posix-sema.c posix-io.c \ +@HAVE_DOSISH_SYSTEM_FALSE@ $(am__append_1) +@HAVE_DOSISH_SYSTEM_TRUE@system_components = w32-util.c w32-sema.c \ +@HAVE_DOSISH_SYSTEM_TRUE@ $(am__append_1) +@HAVE_DOSISH_SYSTEM_FALSE@system_components_not_extra = +@HAVE_DOSISH_SYSTEM_TRUE@system_components_not_extra = w32-io.c +@HAVE_GPGSM_FALSE@gpgsm_components = +@HAVE_GPGSM_TRUE@gpgsm_components = engine-gpgsm.c +@HAVE_ASSUAN_FALSE@assuan_components = +@HAVE_ASSUAN_TRUE@assuan_components = assuan-support.c engine-assuan.c +@HAVE_GPGCONF_FALSE@gpgconf_components = +@HAVE_GPGCONF_TRUE@gpgconf_components = engine-gpgconf.c +@HAVE_G13_FALSE@g13_components = +@HAVE_G13_TRUE@g13_components = engine-g13.c +@HAVE_UISERVER_FALSE@uiserver_components = +@HAVE_UISERVER_TRUE@uiserver_components = engine-uiserver.c + +# These are the source files common to all library versions. We used +# to build a non-installed library for that, but that does not work +# correctly on all platforms (in particular, one can not specify the +# right linking order with libtool, as the non-installed version has +# unresolved symbols to the thread module. +main_sources = \ + 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 sig-notation.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 getauditlog.c \ + opassuan.c passwd.c \ + engine.h engine-backend.h engine.c engine-gpg.c status-table.c \ + $(gpgsm_components) $(assuan_components) $(gpgconf_components) \ + $(uiserver_components) \ + $(g13_components) vfs-mount.c vfs-create.c \ + gpgconf.c \ + sema.h priv-io.h $(system_components) dirinfo.c \ + debug.c debug.h gpgme.c version.c error.c + +libgpgme_la_SOURCES = $(main_sources) \ + ath.h ath.c $(system_components_not_extra) + +libgpgme_pthread_la_SOURCES = $(main_sources) \ + ath.h ath-pthread.c $(system_components_not_extra) + +@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_SOURCES = $(main_sources) ath.h ath.c w32-glib-io.c +@BUILD_W32_QT_TRUE@libgpgme_qt_la_SOURCES = $(main_sources) ath.h ath.c w32-qt-io.cpp \ +@BUILD_W32_QT_TRUE@ kdpipeiodevice.h kdpipeiodevice.cpp kdpipeiodevice.moc + +# FIXME: Add extra depedency: moc_kdpipeiodevice.cpp + +# These are built sources (normally). +# moc_kdpipeiodevice.cpp: kdpipeiodevice.h +# $(MOC4) -o $@ $< +# +# kdpipeiodevice.moc: kdpipeiodevice.cpp +# $(MOC4) -o $@ $< + +# We use a global CFLAGS and CPPFLAGS setting for all library +# versions, because then every object file is only compiled once. +AM_CPPFLAGS = @GPG_ERROR_CFLAGS@ @QT4_CORE_CFLAGS@ +AM_CFLAGS = @LIBASSUAN_CFLAGS@ @GLIB_CFLAGS@ @QT4_CORE_CFLAGS@ +@HAVE_W32_SYSTEM_TRUE@RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) +@HAVE_W32_SYSTEM_TRUE@LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE) +@HAVE_W32_SYSTEM_TRUE@SUFFIXES = .rc .lo +@HAVE_W32_SYSTEM_FALSE@gpgme_res = +@HAVE_W32_SYSTEM_TRUE@gpgme_res = versioninfo.lo +@HAVE_W32_SYSTEM_FALSE@no_undefined = +@HAVE_W32_SYSTEM_TRUE@no_undefined = -no-undefined +@HAVE_W32_SYSTEM_FALSE@export_symbols = +@HAVE_W32_SYSTEM_TRUE@export_symbols = -export-symbols $(srcdir)/gpgme.def +@HAVE_W32_SYSTEM_FALSE@gpgme_deps = +@HAVE_W32_SYSTEM_TRUE@gpgme_deps = $(gpgme_res) gpgme.def +libgpgme_la_LDFLAGS = $(no_undefined) $(export_symbols) \ + $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ + +libgpgme_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) +libgpgme_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + @GPG_ERROR_LIBS@ + +libgpgme_pthread_la_LDFLAGS = $(no_undefined) $(export_symbols) \ + $(libgpgme_version_script_cmd) -version-info \ + @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ + +libgpgme_pthread_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers +libgpgme_pthread_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ + -lpthread @GPG_ERROR_LIBS@ + +@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_LDFLAGS = $(no_undefined) \ +@BUILD_W32_GLIB_TRUE@ $(export_symbols) $(libgpgme_version_script_cmd) -version-info \ +@BUILD_W32_GLIB_TRUE@ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ + +@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_DEPENDENCIES = @LTLIBOBJS@ \ +@BUILD_W32_GLIB_TRUE@ $(srcdir)/libgpgme.vers $(gpgme_deps) + +@BUILD_W32_GLIB_TRUE@libgpgme_glib_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ +@BUILD_W32_GLIB_TRUE@ @GPG_ERROR_LIBS@ @GLIB_LIBS@ + +@BUILD_W32_QT_TRUE@libgpgme_qt_la_LDFLAGS = $(no_undefined) \ +@BUILD_W32_QT_TRUE@ $(export_symbols) $(libgpgme_version_script_cmd) -version-info \ +@BUILD_W32_QT_TRUE@ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ + +@BUILD_W32_QT_TRUE@libgpgme_qt_la_DEPENDENCIES = @LTLIBOBJS@ $(srcdir)/libgpgme.vers $(gpgme_deps) +@BUILD_W32_QT_TRUE@libgpgme_qt_la_LIBADD = $(gpgme_res) @LIBASSUAN_LIBS@ @LTLIBOBJS@ \ +@BUILD_W32_QT_TRUE@ @GPG_ERROR_LIBS@ @QT4_CORE_LIBS@ + +gpgme_tool_LDADD = libgpgme.la @LIBASSUAN_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .rc .lo .c .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +versioninfo.rc: $(top_builddir)/config.status $(srcdir)/versioninfo.rc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpgme.h: $(top_builddir)/config.status $(srcdir)/gpgme.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +gpgme-config: $(top_builddir)/config.status $(srcdir)/gpgme-config.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libgpgme-glib.la: $(libgpgme_glib_la_OBJECTS) $(libgpgme_glib_la_DEPENDENCIES) + $(libgpgme_glib_la_LINK) $(am_libgpgme_glib_la_rpath) $(libgpgme_glib_la_OBJECTS) $(libgpgme_glib_la_LIBADD) $(LIBS) +libgpgme-pthread.la: $(libgpgme_pthread_la_OBJECTS) $(libgpgme_pthread_la_DEPENDENCIES) + $(libgpgme_pthread_la_LINK) $(am_libgpgme_pthread_la_rpath) $(libgpgme_pthread_la_OBJECTS) $(libgpgme_pthread_la_LIBADD) $(LIBS) +libgpgme-qt.la: $(libgpgme_qt_la_OBJECTS) $(libgpgme_qt_la_DEPENDENCIES) + $(libgpgme_qt_la_LINK) $(am_libgpgme_qt_la_rpath) $(libgpgme_qt_la_OBJECTS) $(libgpgme_qt_la_LIBADD) $(LIBS) +libgpgme.la: $(libgpgme_la_OBJECTS) $(libgpgme_la_DEPENDENCIES) + $(libgpgme_la_LINK) -rpath $(libdir) $(libgpgme_la_OBJECTS) $(libgpgme_la_LIBADD) $(LIBS) +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)" + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +gpgme-tool$(EXEEXT): $(gpgme_tool_OBJECTS) $(gpgme_tool_DEPENDENCIES) + @rm -f gpgme-tool$(EXEEXT) + $(LINK) $(gpgme_tool_OBJECTS) $(gpgme_tool_LDADD) $(LIBS) +gpgme-w32spawn$(EXEEXT): $(gpgme_w32spawn_OBJECTS) $(gpgme_w32spawn_DEPENDENCIES) + @rm -f gpgme-w32spawn$(EXEEXT) + $(LINK) $(gpgme_w32spawn_OBJECTS) $(gpgme_w32spawn_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/funopen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/setenv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/stpcpy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ttyname_r.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/vasprintf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/assuan-support.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ath-pthread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ath.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conversion.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-compat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-fd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data-user.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decrypt-verify.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decrypt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirinfo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encrypt-sign.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encrypt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-assuan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-g13.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-gpg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-gpgconf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-gpgsm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine-uiserver.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engine.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/export.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genkey.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get-env.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getauditlog.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgconf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-tool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme-w32spawn.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kdpipeiodevice.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keylist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/op-support.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opassuan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passphrase.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passwd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-sema.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/progress.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sig-notation.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sign.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trust-item.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trustlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vfs-create.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vfs-mount.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-ce.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-glib-io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-qt-io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-sema.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/w32-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait-global.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait-private.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait-user.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wait.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-m4dataDATA: $(m4data_DATA) + @$(NORMAL_INSTALL) + test -z "$(m4datadir)" || $(MKDIR_P) "$(DESTDIR)$(m4datadir)" + @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(m4datadir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(m4datadir)" || exit $$?; \ + done + +uninstall-m4dataDATA: + @$(NORMAL_UNINSTALL) + @list='$(m4data_DATA)'; test -n "$(m4datadir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(m4datadir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(m4datadir)" && rm -f $$files +install-nodist_includeHEADERS: $(nodist_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-nodist_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(DATA) \ + $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(m4datadir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libexecPROGRAMS \ + clean-libtool clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-data-local install-m4dataDATA \ + install-nodist_includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binSCRIPTS install-libLTLIBRARIES \ + install-libexecPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binSCRIPTS uninstall-libLTLIBRARIES \ + uninstall-libexecPROGRAMS uninstall-local uninstall-m4dataDATA \ + uninstall-nodist_includeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \ + clean-noinstPROGRAMS ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binSCRIPTS install-data install-data-am \ + install-data-local install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-libexecPROGRAMS \ + install-m4dataDATA install-man install-nodist_includeHEADERS \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binSCRIPTS uninstall-libLTLIBRARIES \ + uninstall-libexecPROGRAMS uninstall-local uninstall-m4dataDATA \ + uninstall-nodist_includeHEADERS + + +@HAVE_W32_SYSTEM_TRUE@.rc.lo: +@HAVE_W32_SYSTEM_TRUE@ $(LTRCCOMPILE) -i "$<" -o "$@" + +@HAVE_W32_SYSTEM_TRUE@install-def-file: +@HAVE_W32_SYSTEM_TRUE@ $(INSTALL) $(srcdir)/gpgme.def $(DESTDIR)$(libdir)/gpgme.def + +@HAVE_W32_SYSTEM_TRUE@uninstall-def-file: +@HAVE_W32_SYSTEM_TRUE@ -rm $(DESTDIR)$(libdir)/gpgme.def +@HAVE_W32_SYSTEM_FALSE@install-def-file: +@HAVE_W32_SYSTEM_FALSE@uninstall-def-file: + +install-data-local: install-def-file + +uninstall-local: uninstall-def-file + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/assuan-support.c b/src/assuan-support.c new file mode 100644 index 0000000..5264346 --- /dev/null +++ b/src/assuan-support.c @@ -0,0 +1,256 @@ +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> +#include <errno.h> + +#include "assuan.h" + +#include "gpgme.h" +#include "ath.h" +#include "priv-io.h" +#include "debug.h" + + +struct assuan_malloc_hooks _gpgme_assuan_malloc_hooks = + { + malloc, + realloc, + free + }; + + +int +_gpgme_assuan_log_cb (assuan_context_t ctx, void *hook, + unsigned int cat, const char *msg) +{ + if (msg == NULL) + return 1; + + _gpgme_debug (DEBUG_ASSUAN, "%s", msg); + return 0; +} + + +static void +my_usleep (assuan_context_t ctx, unsigned int usec) +{ + /* FIXME: Add to ath. */ + __assuan_usleep (ctx, usec); +} + + +/* Create a pipe with an inheritable end. */ +static int +my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx) +{ + int res; + int gfds[2]; + + res = _gpgme_io_pipe (gfds, inherit_idx); + + /* For now... */ + fds[0] = (assuan_fd_t) gfds[0]; + fds[1] = (assuan_fd_t) gfds[1]; + + return res; +} + + +/* Close the given file descriptor, created with _assuan_pipe or one + of the socket functions. */ +static int +my_close (assuan_context_t ctx, assuan_fd_t fd) +{ + return _gpgme_io_close ((int) fd); +} + + +static ssize_t +my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) +{ + return _gpgme_io_read ((int) fd, buffer, size); +} + + +static ssize_t +my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size) +{ + return _gpgme_io_write ((int) fd, buffer, size); +} + + +static int +my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg, + int flags) +{ +#ifdef HAVE_W32_SYSTEM + gpg_err_set_errno (ENOSYS); + return -1; +#else + return _gpgme_io_recvmsg ((int) fd, msg, flags); +#endif +} + + + +static int +my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg, + int flags) +{ +#ifdef HAVE_W32_SYSTEM + gpg_err_set_errno (ENOSYS); + return -1; +#else + return _gpgme_io_sendmsg ((int) fd, msg, flags); +#endif +} + + +/* If NAME is NULL, don't exec, just fork. FD_CHILD_LIST is modified + to reflect the value of the FD in the peer process (on + Windows). */ +static int +my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name, + const char **argv, + assuan_fd_t fd_in, assuan_fd_t fd_out, + assuan_fd_t *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue, unsigned int flags) +{ + int err; + struct spawn_fd_item_s *fd_items; + int i; + + assert (name); + + if (! name) + { + gpg_err_set_errno (ENOSYS); + return -1; + } + + i = 0; + if (fd_child_list) + { + while (fd_child_list[i] != ASSUAN_INVALID_FD) + i++; + } + /* fd_in, fd_out, terminator */ + i += 3; + fd_items = calloc (i, sizeof (struct spawn_fd_item_s)); + if (! fd_items) + return -1; + i = 0; + if (fd_child_list) + { + while (fd_child_list[i] != ASSUAN_INVALID_FD) + { + fd_items[i].fd = (int) fd_child_list[i]; + fd_items[i].dup_to = -1; + i++; + } + } + if (fd_in != ASSUAN_INVALID_FD) + { + fd_items[i].fd = (int) fd_in; + fd_items[i].dup_to = 0; + i++; + } + if (fd_out != ASSUAN_INVALID_FD) + { + fd_items[i].fd = (int) fd_out; + fd_items[i].dup_to = 1; + i++; + } + fd_items[i].fd = -1; + fd_items[i].dup_to = -1; + + err = _gpgme_io_spawn (name, (char*const*)argv, IOSPAWN_FLAG_NOCLOSE, + fd_items, atfork, atforkvalue, r_pid); + if (! err) + { + i = 0; + + if (fd_child_list) + { + while (fd_child_list[i] != ASSUAN_INVALID_FD) + { + fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name; + i++; + } + } + } + free (fd_items); + return err; +} + + +/* If action is 0, like waitpid. If action is 1, just release the PID? */ +static pid_t +my_waitpid (assuan_context_t ctx, pid_t pid, + int nowait, int *status, int options) +{ +#ifdef HAVE_W32_SYSTEM + CloseHandle ((HANDLE) pid); +#else + /* We can't just release the PID, a waitpid is mandatory. But + NOWAIT in POSIX systems just means the caller already did the + waitpid for this child. */ + if (! nowait) + return _gpgme_ath_waitpid (pid, status, options); +#endif + return 0; +} + + + + +static int +my_socketpair (assuan_context_t ctx, int namespace, int style, + int protocol, assuan_fd_t filedes[2]) +{ +#ifdef HAVE_W32_SYSTEM + gpg_err_set_errno (ENOSYS); + return -1; +#else + /* FIXME: Debug output missing. */ + return __assuan_socketpair (ctx, namespace, style, protocol, filedes); +#endif +} + + +static int +my_socket (assuan_context_t ctx, int namespace, int style, int protocol) +{ + return _gpgme_io_socket (namespace, style, protocol); +} + + +static int +my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr, + socklen_t length) +{ + return _gpgme_io_connect (sock, addr, length); +} + + +struct assuan_system_hooks _gpgme_assuan_system_hooks = + { + ASSUAN_SYSTEM_HOOKS_VERSION, + my_usleep, + my_pipe, + my_close, + my_read, + my_write, + my_recvmsg, + my_sendmsg, + my_spawn, + my_waitpid, + my_socketpair, + my_socket, + my_connect + }; + diff --git a/src/ath-pthread.c b/src/ath-pthread.c new file mode 100644 index 0000000..9684afb --- /dev/null +++ b/src/ath-pthread.c @@ -0,0 +1,186 @@ +/* ath-pthread.c - pthread module for self-adapting thread-safeness library + 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 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <errno.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +#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. */ +} + + +uintptr_t +ath_self (void) +{ + return (uintptr_t) pthread_self (); +} + + +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/src/ath.c b/src/ath.c new file mode 100644 index 0000000..ab65f7e --- /dev/null +++ b/src/ath.c @@ -0,0 +1,214 @@ +/* ath.c - Thread-safeness library. + 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 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +#endif +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifndef HAVE_W32_SYSTEM +#include <sys/wait.h> +#endif + +#ifdef _MSC_VER + typedef long ssize_t; + typedef int pid_t; +#endif + +#include "ath.h" + + +#define MUTEX_UNLOCKED ((ath_mutex_t) 0) +#define MUTEX_LOCKED ((ath_mutex_t) 1) +#define MUTEX_DESTROYED ((ath_mutex_t) 2) + + +#ifdef HAVE_W32_SYSTEM +#include <windows.h> +uintptr_t +ath_self (void) +{ + return (uintptr_t) GetCurrentThreadId (); +} +#else +# ifdef __linux +#include <sys/syscall.h> +uintptr_t +ath_self (void) +{ + /* Just to catch users who don't use gpgme-pthread. */ + return (uintptr_t) syscall (__NR_gettid); +} +# else +uintptr_t +ath_self (void) +{ + return (uintptr_t) getpid (); +} +# endif +#endif + + +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) +{ +#if defined(HAVE_W32CE_SYSTEM) && defined(_MSC_VER) + return -1; /* Not supported. */ +#else + return read (fd, buf, nbytes); +#endif +} + + +ssize_t +ath_write (int fd, const void *buf, size_t nbytes) +{ +#if defined(HAVE_W32CE_SYSTEM) && defined(_MSC_VER) + return -1; /* Not supported. */ +#else + return write (fd, buf, nbytes); +#endif +} + + +ssize_t +ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return select (nfd, rset, wset, eset, timeout); +#endif +} + + +ssize_t +ath_waitpid (pid_t pid, int *status, int options) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return waitpid (pid, status, options); +#endif +} + + +int +ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return accept (s, addr, length_ptr); +#endif +} + + +int +ath_connect (int s, const struct sockaddr *addr, socklen_t length) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return connect (s, addr, length); +#endif +} + + +int +ath_sendmsg (int s, const struct msghdr *msg, int flags) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return sendmsg (s, msg, flags); +#endif +} + + +int +ath_recvmsg (int s, struct msghdr *msg, int flags) +{ +#ifdef HAVE_W32_SYSTEM + return -1; /* Not supported. */ +#else + return recvmsg (s, msg, flags); +#endif +} diff --git a/src/ath.h b/src/ath.h new file mode 100644 index 0000000..9ada550 --- /dev/null +++ b/src/ath.h @@ -0,0 +1,101 @@ +/* ath.h - Interfaces for thread-safeness library. + 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 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. */ + +#ifndef ATH_H +#define ATH_H + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_W32_SYSTEM + /* fixme: Check how we did it in libgcrypt. */ + struct msghdr { int dummy; }; + typedef int socklen_t; +# if defined(HAVE_W32CE_SYSTEM) && defined(_MSC_VER) +# include <winsock2.h> +# endif +# include <windows.h> +# include <io.h> + +#else /*!HAVE_W32_SYSTEM*/ + +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +# endif +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# include <sys/socket.h> + +#endif /*!HAVE_W32_SYSTEM*/ + + + +/* 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; + +uintptr_t ath_self (void); + +/* 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); + +#endif /* ATH_H */ diff --git a/src/context.h b/src/context.h new file mode 100644 index 0000000..69d8d9b --- /dev/null +++ b/src/context.h @@ -0,0 +1,138 @@ +/* context.h - Definitions for a GPGME context. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2010 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef CONTEXT_H +#define CONTEXT_H + +#include "gpgme.h" +#include "engine.h" +#include "wait.h" +#include "sema.h" + + +extern gpgme_error_t _gpgme_selftest; + +/* 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, OPDATA_ASSUAN, OPDATA_VFS_MOUNT, + OPDATA_PASSWD + } ctx_op_data_id_t; + + +/* "gpgmeres" in ASCII. */ +#define CTX_OP_DATA_MAGIC 0x736572656d677067ULL +struct ctx_op_data +{ + /* A magic word just to make sure people don't deallocate something + that ain't a result structure. */ + unsigned long long magic; + + /* The next element in the linked list, or NULL if this is the last + element. Used by op data structures linked into a context. */ + 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 deallocation routine is necessary. */ + void (*cleanup) (void *hook); + + /* The hook that points to the operation data. */ + void *hook; + + /* The number of outstanding references. */ + int references; +}; +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 +{ + DECLARE_LOCK (lock); + + /* True if the context was canceled asynchronously. */ + int canceled; + + /* The engine info for this context. */ + gpgme_engine_info_t engine_info; + + /* The protocol used by this context. */ + gpgme_protocol_t protocol; + + /* The running engine process. */ + engine_t engine; + + /* Engine's sub protocol. */ + gpgme_protocol_t sub_protocol; + + /* 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 signature notations for this context. */ + gpgme_sig_notation_t sig_notations; + + /* 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/src/conversion.c b/src/conversion.c new file mode 100644 index 0000000..356200c --- /dev/null +++ b/src/conversion.c @@ -0,0 +1,414 @@ +/* conversion.c - String conversion helper functions. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2007 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_TYPES_H + /* Solaris 8 needs sys/types.h before time.h. */ +# include <sys/types.h> +#endif +#include <time.h> +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "debug.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_syserror (); + + *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. If BINARY is 1, then '\0' + characters are allowed in the output. */ +gpgme_error_t +_gpgme_decode_percent_string (const char *src, char **destp, size_t len, + int binary) +{ + 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_syserror (); + + *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 && !binary) + { + /* A binary zero is not representable in a C + string. */ + *(dest++) = '\\'; + *(dest++) = '0'; + } + else + *((unsigned char *) dest++) = val; + src += 3; + } + } + } + *(dest++) = 0; + + return 0; +} + + +/* Encode the string SRC with percent escaping 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. If BINARY is 1, then '\0' + characters are allowed in the output. */ +gpgme_error_t +_gpgme_encode_percent_string (const char *src, char **destp, size_t len) +{ + size_t destlen; + char *dest; + const char *str; + + destlen = 0; + str = src; + /* We percent-escape the + character because the user might need a + "percent plus" escaped string (special gpg format). But we + percent-escape the space character, which works with and without + the special plus format. */ + while (*str) + { + if (*str == '+' || *str == '\"' || *str == '%' + || *(const unsigned char *)str <= 0x20) + destlen += 3; + else + destlen++; + str++; + } + /* Terminating nul byte. */ + destlen++; + + /* Set up the destination buffer. */ + if (len) + { + if (len < destlen); + return gpg_error (GPG_ERR_INTERNAL); + + dest = *destp; + } + else + { + /* The converted string will never be larger than the original + string. */ + dest = malloc (destlen); + if (!dest) + return gpg_error_from_syserror (); + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src == '+' || *src == '\"' || *src == '%' + || *(const unsigned char *)src <= 0x20) + { + snprintf (dest, 4, "%%%02X", *(unsigned char *)src); + dest += 3; + } + else + *(dest++) = *src; + src++; + } + *(dest++) = 0; + + return 0; +} + + +#ifdef HAVE_W32_SYSTEM +static time_t +_gpgme_timegm (struct tm *tm) +{ + /* This one is thread safe. */ + SYSTEMTIME st; + FILETIME ft; + unsigned long long cnsecs; + + st.wYear = tm->tm_year + 1900; + st.wMonth = tm->tm_mon + 1; + st.wDay = tm->tm_mday; + st.wHour = tm->tm_hour; + st.wMinute = tm->tm_min; + st.wSecond = tm->tm_sec; + st.wMilliseconds = 0; /* Not available. */ + st.wDayOfWeek = 0; /* Ignored. */ + + /* System time is UTC thus the conversion is pretty easy. */ + if (!SystemTimeToFileTime (&st, &ft)) + { + gpg_err_set_errno (EINVAL); + return (time_t)(-1); + } + + cnsecs = (((unsigned long long)ft.dwHighDateTime << 32) + | ft.dwLowDateTime); + cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */ + return (time_t)(cnsecs / 10000000ULL); +} +#endif + + +/* 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); + + if (endp) + *endp = (char*)(timestamp + 15); + + /* 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); + +#ifdef HAVE_W32_SYSTEM + return _gpgme_timegm (&buf); +#else +#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 */ +#endif /* !HAVE_W32_SYSTEM */ + } + else + return (time_t)strtoul (timestamp, endp, 10); +} diff --git a/src/data-compat.c b/src/data-compat.c new file mode 100644 index 0000000..39c743e --- /dev/null +++ b/src/data-compat.c @@ -0,0 +1,254 @@ +/* data-compat.c - Compatibility interfaces for data objects. + Copyright (C) 2002, 2003, 2004, 2007 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#include <stdlib.h> + +#include "data.h" +#include "util.h" +#include "debug.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 *r_dh, const char *fname, + FILE *stream, off_t offset, size_t length) +{ +#if defined (HAVE_W32CE_SYSTEM) && defined (_MSC_VER) + return gpgme_error (GPG_ERR_NOT_IMPLEMENTED); +#else + gpgme_error_t err; + char *buf = NULL; + int res; + + TRACE_BEG4 (DEBUG_DATA, "gpgme_data_new_from_filepart", r_dh, + "file_name=%s, stream=%p, offset=%lli, length=%u", + fname, stream, offset, length); + + if (stream && fname) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (fname) + stream = fopen (fname, "rb"); + if (!stream) + return TRACE_ERR (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 TRACE_ERR (gpg_error_from_errno (saved_errno)); + } + + buf = malloc (length); + if (!buf) + { + int saved_errno = errno; + if (fname) + fclose (stream); + return TRACE_ERR (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 TRACE_ERR (gpg_error_from_errno (saved_errno)); + } + + if (fname) + fclose (stream); + + err = gpgme_data_new (r_dh); + if (err) + { + if (buf) + free (buf); + return err; + } + + (*r_dh)->data.mem.buffer = buf; + (*r_dh)->data.mem.size = length; + (*r_dh)->data.mem.length = length; + + return TRACE_SUC1 ("r_dh=%p", *r_dh); +#endif +} + + +/* 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 *r_dh, const char *fname, int copy) +{ +#if defined (HAVE_W32CE_SYSTEM) && defined (_MSC_VER) + return gpgme_error (GPG_ERR_NOT_IMPLEMENTED); +#else + gpgme_error_t err; + struct stat statbuf; + TRACE_BEG3 (DEBUG_DATA, "gpgme_data_new_from_filepart", r_dh, + "file_name=%s, copy=%i (%s)", fname, copy, copy ? "yes" : "no"); + + if (!fname || !copy) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (stat (fname, &statbuf) < 0) + return TRACE_ERR (gpg_error_from_errno (errno)); + + err = gpgme_data_new_from_filepart (r_dh, fname, NULL, 0, statbuf.st_size); + return TRACE_ERR (err); +#endif +} + + +static int +gpgme_error_to_errno (gpgme_error_t err) +{ + int res = gpg_err_code_to_errno (err); + + if (!err) + { + switch (gpg_err_code (err)) + { + case GPG_ERR_EOF: + res = 0; + break; + case GPG_ERR_INV_VALUE: + res = EINVAL; + break; + case GPG_ERR_NOT_SUPPORTED: + res = ENOSYS; + break; + default: + /* FIXME: Yeah, well. */ + res = EINVAL; + break; + } + } + TRACE3 (DEBUG_DATA, "gpgme:gpgme_error_to_errno", 0, + "mapping %s <%s> to: %s", gpgme_strerror (err), + gpgme_strsource (err), strerror (res)); + gpg_err_set_errno (res); + return res ? -1 : 0; +} + + +static ssize_t +old_user_read (gpgme_data_t dh, void *buffer, size_t size) +{ + gpgme_error_t err; + size_t amt; + TRACE_BEG2 (DEBUG_DATA, "gpgme:old_user_read", dh, + "buffer=%p, size=%u", buffer, size); + + err = (*dh->data.old_user.cb) (dh->data.old_user.handle, + buffer, size, &amt); + if (err) + return TRACE_SYSRES (gpgme_error_to_errno (err)); + return TRACE_SYSRES (amt); +} + + +static off_t +old_user_seek (gpgme_data_t dh, off_t offset, int whence) +{ + gpgme_error_t err; + TRACE_BEG2 (DEBUG_DATA, "gpgme:old_user_seek", dh, + "offset=%llu, whence=%i", offset, whence); + + if (whence != SEEK_SET || offset) + { + gpg_err_set_errno (EINVAL); + return TRACE_SYSRES (-1); + } + err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL); + if (err) + return TRACE_SYSRES (gpgme_error_to_errno (err)); + return TRACE_SYSRES (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 *r_dh, + int (*read_cb) (void *, char *, size_t, size_t *), + void *read_cb_value) +{ + gpgme_error_t err; + TRACE_BEG2 (DEBUG_DATA, "gpgme_data_new_with_read_cb", r_dh, + "read_cb=%p/%p", read_cb, read_cb_value); + + err = _gpgme_data_new (r_dh, &old_user_cbs); + + if (err) + return TRACE_ERR (err); + + (*r_dh)->data.old_user.cb = read_cb; + (*r_dh)->data.old_user.handle = read_cb_value; + return TRACE_ERR (0); +} + + +gpgme_error_t +gpgme_data_rewind (gpgme_data_t dh) +{ + gpgme_error_t err; + TRACE_BEG (DEBUG_DATA, "gpgme_data_rewind", dh); + + err = (gpgme_data_seek (dh, 0, SEEK_SET) == -1) + ? gpg_error_from_errno (errno) : 0; + + return TRACE_ERR (err); +} diff --git a/src/data-fd.c b/src/data-fd.c new file mode 100644 index 0000000..388b45c --- /dev/null +++ b/src/data-fd.c @@ -0,0 +1,142 @@ +/* data-fd.c - A file descripor 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include "debug.h" +#include "data.h" + + + +#if defined(HAVE_W32CE_SYSTEM) && !defined(__MINGW32CE__) +/* We need to provide replacements for read, write and lseek. They + are taken from the cegcc runtime files, written by Pedro Alves + <pedro_alves@portugalmail.pt> in Feb 2007 and placed in the public + domain. (cf. cegcc/src/mingw/mingwex/wince/) */ + +#include <windows.h> + +static int +read (int fildes, void *buf, unsigned int bufsize) +{ + DWORD NumberOfBytesRead; + if (bufsize > 0x7fffffff) + bufsize = 0x7fffffff; + if (!ReadFile ((HANDLE) fildes, buf, bufsize, &NumberOfBytesRead, NULL)) + return -1; + return (int) NumberOfBytesRead; +} + +static int +write (int fildes, const void *buf, unsigned int bufsize) +{ + DWORD NumberOfBytesWritten; + if (bufsize > 0x7fffffff) + bufsize = 0x7fffffff; + if (!WriteFile ((HANDLE) fildes, buf, bufsize, &NumberOfBytesWritten, NULL)) + return -1; + return (int) NumberOfBytesWritten; +} + +static long +lseek (int fildes, long offset, int whence) +{ + DWORD mode; + switch (whence) + { + case SEEK_SET: + mode = FILE_BEGIN; + break; + case SEEK_CUR: + mode = FILE_CURRENT; + break; + case SEEK_END: + mode = FILE_END; + break; + default: + /* Specify an invalid mode so SetFilePointer catches it. */ + mode = (DWORD)-1; + } + return (long) SetFilePointer ((HANDLE) fildes, offset, NULL, mode); +} +#endif /*HAVE_W32CE_SYSTEM && !__MINGW32CE__*/ + + + +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 int +fd_get_fd (gpgme_data_t dh) +{ + return (dh->data.fd); +} + + +static struct _gpgme_data_cbs fd_cbs = + { + fd_read, + fd_write, + fd_seek, + NULL, + fd_get_fd + }; + + +gpgme_error_t +gpgme_data_new_from_fd (gpgme_data_t *r_dh, int fd) +{ + gpgme_error_t err; + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_new_from_fd", r_dh, "fd=0x%x", fd); + + err = _gpgme_data_new (r_dh, &fd_cbs); + if (err) + return TRACE_ERR (err); + + (*r_dh)->data.fd = fd; + return TRACE_SUC1 ("dh=%p", *r_dh); +} diff --git a/src/data-mem.c b/src/data-mem.c new file mode 100644 index 0000000..eda695a --- /dev/null +++ b/src/data-mem.c @@ -0,0 +1,282 @@ +/* data-mem.c - A memory based data object. + Copyright (C) 2002, 2003, 2004, 2007 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <assert.h> +#include <string.h> + +#include "data.h" +#include "util.h" +#include "debug.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) + { + gpg_err_set_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)) + { + gpg_err_set_errno (EINVAL); + return -1; + } + dh->data.mem.offset += offset; + break; + case SEEK_END: + if (offset > 0 || -offset > dh->data.mem.length) + { + gpg_err_set_errno (EINVAL); + return -1; + } + dh->data.mem.offset = dh->data.mem.length - offset; + break; + default: + gpg_err_set_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, + NULL + }; + + +/* Create a new data buffer and return it in R_DH. */ +gpgme_error_t +gpgme_data_new (gpgme_data_t *r_dh) +{ + gpgme_error_t err; + TRACE_BEG (DEBUG_DATA, "gpgme_data_new", r_dh); + + err = _gpgme_data_new (r_dh, &mem_cbs); + + if (err) + return TRACE_ERR (err); + + return TRACE_SUC1 ("dh=%p", *r_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) +{ + gpgme_error_t err; + TRACE_BEG4 (DEBUG_DATA, "gpgme_data_new_from_mem", r_dh, + "buffer=%p, size=%u, copy=%i (%s)", buffer, size, + copy, copy ? "yes" : "no"); + + err = _gpgme_data_new (r_dh, &mem_cbs); + if (err) + return TRACE_ERR (err); + + if (copy) + { + char *bufcpy = malloc (size); + if (!bufcpy) + { + int saved_errno = errno; + _gpgme_data_release (*r_dh); + return TRACE_ERR (gpg_error_from_errno (saved_errno)); + } + memcpy (bufcpy, buffer, size); + (*r_dh)->data.mem.buffer = bufcpy; + } + else + (*r_dh)->data.mem.orig_buffer = buffer; + + (*r_dh)->data.mem.size = size; + (*r_dh)->data.mem.length = size; + return TRACE_SUC1 ("dh=%p", *r_dh); +} + + +/* Destroy the data buffer DH and return a pointer to its content. + The memory has be to released with gpgme_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) +{ + char *str = NULL; + + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_release_and_get_mem", dh, + "r_len=%p", r_len); + + if (!dh || dh->cbs != &mem_cbs) + { + gpgme_data_release (dh); + TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + return NULL; + } + + str = dh->data.mem.buffer; + if (!str && dh->data.mem.orig_buffer) + { + str = malloc (dh->data.mem.length); + if (!str) + { + int saved_errno = errno; + gpgme_data_release (dh); + TRACE_ERR (gpg_error_from_errno (saved_errno)); + return NULL; + } + memcpy (str, dh->data.mem.orig_buffer, dh->data.mem.length); + } + else + /* Prevent mem_release from releasing the buffer memory. We must + not fail from this point. */ + dh->data.mem.buffer = NULL; + + if (r_len) + *r_len = dh->data.mem.length; + + gpgme_data_release (dh); + + if (r_len) + { + TRACE_SUC2 ("buffer=%p, len=%u", str, *r_len); + } + else + { + TRACE_SUC1 ("buffer=%p", str); + } + return str; +} + + +/* Release the memory returned by gpgme_data_release_and_get_mem(). */ +void +gpgme_free (void *buffer) +{ + TRACE (DEBUG_DATA, "gpgme_free", buffer); + + if (buffer) + free (buffer); +} diff --git a/src/data-stream.c b/src/data-stream.c new file mode 100644 index 0000000..0e84065 --- /dev/null +++ b/src/data-stream.c @@ -0,0 +1,108 @@ +/* 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include "debug.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; + +#ifdef HAVE_FSEEKO + return ftello (dh->data.stream); +#else + return ftell (dh->data.stream); +#endif +} + + +static int +stream_get_fd (gpgme_data_t dh) +{ + fflush (dh->data.stream); + return fileno (dh->data.stream); +} + + +static struct _gpgme_data_cbs stream_cbs = + { + stream_read, + stream_write, + stream_seek, + NULL, + stream_get_fd + }; + + +gpgme_error_t +gpgme_data_new_from_stream (gpgme_data_t *r_dh, FILE *stream) +{ + gpgme_error_t err; + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_new_from_stream", r_dh, "stream=%p", + stream); + + err = _gpgme_data_new (r_dh, &stream_cbs); + if (err) + return TRACE_ERR (err); + + (*r_dh)->data.stream = stream; + return TRACE_SUC1 ("dh=%p", *r_dh); +} diff --git a/src/data-user.c b/src/data-user.c new file mode 100644 index 0000000..65065e7 --- /dev/null +++ b/src/data-user.c @@ -0,0 +1,104 @@ +/* data-user.c - A user callback 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#include <errno.h> + +#include "debug.h" +#include "data.h" + + +static ssize_t +user_read (gpgme_data_t dh, void *buffer, size_t size) +{ + if (!dh->data.user.cbs->read) + { + gpg_err_set_errno (EBADF); + return -1; + } + + 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) +{ + if (!dh->data.user.cbs->write) + { + gpg_err_set_errno (EBADF); + return -1; + } + + 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) +{ + if (!dh->data.user.cbs->seek) + { + gpg_err_set_errno (EBADF); + return -1; + } + + return (*dh->data.user.cbs->seek) (dh->data.user.handle, offset, whence); +} + + +static void +user_release (gpgme_data_t dh) +{ + if (dh->data.user.cbs->release) + (*dh->data.user.cbs->release) (dh->data.user.handle); +} + + +static struct _gpgme_data_cbs user_cbs = + { + user_read, + user_write, + user_seek, + user_release, + NULL + }; + + +gpgme_error_t +gpgme_data_new_from_cbs (gpgme_data_t *r_dh, gpgme_data_cbs_t cbs, void *handle) +{ + gpgme_error_t err; + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_new_from_cbs", r_dh, "handle=%p", handle); + + err = _gpgme_data_new (r_dh, &user_cbs); + if (err) + return TRACE_ERR (err); + + (*r_dh)->data.user.cbs = cbs; + (*r_dh)->data.user.handle = handle; + return TRACE_SUC1 ("dh=%p", *r_dh); +} diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..0a62910 --- /dev/null +++ b/src/data.c @@ -0,0 +1,336 @@ +/* data.c - An abstraction for data objects. + Copyright (C) 2002, 2003, 2004, 2005, 2007 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <errno.h> +#include <string.h> + +#include "gpgme.h" +#include "data.h" +#include "util.h" +#include "ops.h" +#include "priv-io.h" +#include "debug.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_syserror (); + + dh->cbs = cbs; + + *r_dh = dh; + return 0; +} + + +void +_gpgme_data_release (gpgme_data_t dh) +{ + if (!dh) + return; + + if (dh->file_name) + free (dh->file_name); + 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) +{ + ssize_t res; + TRACE_BEG2 (DEBUG_DATA, "gpgme_data_read", dh, + "buffer=%p, size=%u", buffer, size); + + if (!dh) + { + gpg_err_set_errno (EINVAL); + return TRACE_SYSRES (-1); + } + if (!dh->cbs->read) + { + gpg_err_set_errno (ENOSYS); + return TRACE_SYSRES (-1); + } + do + res = (*dh->cbs->read) (dh, buffer, size); + while (res < 0 && errno == EINTR); + + return TRACE_SYSRES (res); +} + + +/* 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) +{ + ssize_t res; + TRACE_BEG2 (DEBUG_DATA, "gpgme_data_write", dh, + "buffer=%p, size=%u", buffer, size); + + if (!dh) + { + gpg_err_set_errno (EINVAL); + return TRACE_SYSRES (-1); + } + if (!dh->cbs->write) + { + gpg_err_set_errno (ENOSYS); + return TRACE_SYSRES (-1); + } + do + res = (*dh->cbs->write) (dh, buffer, size); + while (res < 0 && errno == EINTR); + + return TRACE_SYSRES (res); +} + + +/* 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) +{ + TRACE_BEG2 (DEBUG_DATA, "gpgme_data_seek", dh, + "offset=%lli, whence=%i", offset, whence); + + if (!dh) + { + gpg_err_set_errno (EINVAL); + return TRACE_SYSRES (-1); + } + if (!dh->cbs->seek) + { + gpg_err_set_errno (ENOSYS); + return TRACE_SYSRES (-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 TRACE_SYSRES (offset); +} + + +/* Release the data object with the handle DH. */ +void +gpgme_data_release (gpgme_data_t dh) +{ + TRACE (DEBUG_DATA, "gpgme_data_release", 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) +{ + TRACE1 (DEBUG_DATA, "gpgme_data_get_encoding", dh, + "dh->encoding=%i", dh ? dh->encoding : GPGME_DATA_ENCODING_NONE); + 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) +{ + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_encoding", dh, + "encoding=%i", enc); + if (!dh) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + if (enc < 0 || enc > GPGME_DATA_ENCODING_URL0) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + dh->encoding = enc; + return TRACE_ERR (0); +} + + +/* Set the file name associated with the data object with handle DH to + FILE_NAME. */ +gpgme_error_t +gpgme_data_set_file_name (gpgme_data_t dh, const char *file_name) +{ + TRACE_BEG1 (DEBUG_DATA, "gpgme_data_set_file_name", dh, + "file_name=%s", file_name); + + if (!dh) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (dh->file_name) + free (dh->file_name); + + if (file_name) + { + dh->file_name = strdup (file_name); + if (!dh->file_name) + return TRACE_ERR (gpg_error_from_syserror ()); + } + else + dh->file_name = 0; + + return TRACE_ERR (0); +} + + +/* Get the file name associated with the data object with handle DH, + or NULL if there is none. */ +char * +gpgme_data_get_file_name (gpgme_data_t dh) +{ + if (!dh) + { + TRACE (DEBUG_DATA, "gpgme_data_get_file_name", dh); + return NULL; + } + + TRACE1 (DEBUG_DATA, "gpgme_data_get_file_name", dh, + "dh->file_name=%s", dh->file_name); + return dh->file_name; +} + + +/* Functions to support the wait interface. */ + +gpgme_error_t +_gpgme_data_inbound_handler (void *opaque, int fd) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + gpgme_data_t dh = (gpgme_data_t) data->handler_value; + char buffer[BUFFER_SIZE]; + char *bufp = buffer; + ssize_t buflen; + TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_inbound_handler", dh, + "fd=0x%x", fd); + + buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE); + if (buflen < 0) + return gpg_error_from_syserror (); + if (buflen == 0) + { + _gpgme_io_close (fd); + return TRACE_ERR (0); + } + + do + { + ssize_t amt = gpgme_data_write (dh, bufp, buflen); + if (amt == 0 || (amt < 0 && errno != EINTR)) + return TRACE_ERR (gpg_error_from_syserror ()); + bufp += amt; + buflen -= amt; + } + while (buflen > 0); + return TRACE_ERR (0); +} + + +gpgme_error_t +_gpgme_data_outbound_handler (void *opaque, int fd) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + gpgme_data_t dh = (gpgme_data_t) data->handler_value; + ssize_t nwritten; + TRACE_BEG1 (DEBUG_CTX, "_gpgme_data_outbound_handler", dh, + "fd=0x%x", fd); + + if (!dh->pending_len) + { + ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE); + if (amt < 0) + return TRACE_ERR (gpg_error_from_syserror ()); + if (amt == 0) + { + _gpgme_io_close (fd); + return TRACE_ERR (0); + } + dh->pending_len = amt; + } + + nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len); + if (nwritten == -1 && errno == EAGAIN) + return TRACE_ERR (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 TRACE_ERR (0); + } + + if (nwritten <= 0) + return TRACE_ERR (gpg_error_from_syserror ()); + + if (nwritten < dh->pending_len) + memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten); + dh->pending_len -= nwritten; + return TRACE_ERR (0); +} + + +/* Get the file descriptor associated with DH, if possible. Otherwise + return -1. */ +int +_gpgme_data_get_fd (gpgme_data_t dh) +{ + if (!dh || !dh->cbs->get_fd) + return -1; + return (*dh->cbs->get_fd) (dh); +} diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..1257a8d --- /dev/null +++ b/src/data.h @@ -0,0 +1,134 @@ +/* data.h - Internal data object abstraction interface. + Copyright (C) 2002, 2004, 2005 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. */ + +#ifndef DATA_H +#define DATA_H + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#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); + +/* Get the FD associated with the handle DH, or -1. */ +typedef int (*gpgme_data_get_fd_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; + gpgme_data_get_fd_cb get_fd; +}; + +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; + + /* File name of the data object. */ + char *file_name; + + 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); + +/* Get the file descriptor associated with DH, if possible. Otherwise + return -1. */ +int _gpgme_data_get_fd (gpgme_data_t dh); + +#endif /* DATA_H */ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..34c5d18 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,369 @@ +/* debug.c - helpful output in desperate situations + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <ctype.h> +#include <errno.h> +#include <time.h> +#ifndef HAVE_DOSISH_SYSTEM +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +# endif +# include <fcntl.h> +#endif +#include <assert.h> + +#include "util.h" +#include "ath.h" +#include "sema.h" +#include "debug.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; + + +#ifdef HAVE_TLS +#define FRAME_NR +static __thread int frame_nr = 0; +#endif + +void +_gpgme_debug_frame_begin (void) +{ +#ifdef FRAME_NR + frame_nr++; +#endif +} + +void _gpgme_debug_frame_end (void) +{ +#ifdef FRAME_NR + frame_nr--; +#endif +} + + + +/* 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;; + +#ifdef HAVE_W32CE_SYSTEM + e = _gpgme_w32ce_get_debug_envvar (); +#else /*!HAVE_W32CE_SYSTEM*/ + err = _gpgme_getenv ("GPGME_DEBUG", &e); + if (err) + { + UNLOCK (debug_lock); + return; + } +#endif /*!HAVE_W32CE_SYSTEM*/ + + initialized = 1; + errfp = stderr; + if (e) + { + debug_level = atoi (e); + s1 = strchr (e, PATHSEP_C); + if (s1) + { +#ifndef HAVE_DOSISH_SYSTEM + if (getuid () == geteuid () +#if defined(HAVE_GETGID) && defined(HAVE_GETEGID) + && getgid () == getegid () +#endif + ) + { +#endif + char *p; + FILE *fp; + + s1++; + if (!(s2 = strchr (s1, PATHSEP_C))) + 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); + } + } + UNLOCK (debug_lock); + + if (debug_level > 0) + _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level); +} + + + +/* This should be called as soon as the locks are intialized. It is + required so that the assuan logging gets conncted to the gpgme log + stream as early as possible. */ +void +_gpgme_debug_subsystem_init (void) +{ + debug_init (); +} + + + + +/* Log the formatted string FORMAT at debug level LEVEL or higher. */ +void +_gpgme_debug (int level, const char *format, ...) +{ + va_list arg_ptr; + int saved_errno; + + saved_errno = errno; + if (debug_level < level) + return; + + va_start (arg_ptr, format); + LOCK (debug_lock); + { +#ifdef HAVE_W32CE_SYSTEM + SYSTEMTIME t; + + GetLocalTime (&t); + fprintf (errfp, "GPGME %04d-%02d-%02d %02d:%02d:%02d <0x%04llx> ", + t.wYear, t.wMonth, t.wDay, + t.wHour, t.wMinute, t.wSecond, + (unsigned long long) ath_self ()); +#else + struct tm *tp; + time_t atime = time (NULL); + + tp = localtime (&atime); + fprintf (errfp, "GPGME %04d-%02d-%02d %02d:%02d:%02d <0x%04llx> ", + 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec, + (unsigned long long) ath_self ()); +#endif + } +#ifdef FRAME_NR + { + char spaces[] = " "; + int nr_spaces = sizeof (spaces) - 1; + int nr_columns; + + nr_columns = 2 * (frame_nr - 1); + if (nr_columns > nr_spaces) + nr_columns = nr_spaces; + if (nr_columns < 0) + nr_columns = 0; + spaces[nr_columns] = '\0'; + fprintf (errfp, "%s", spaces); + } +#endif + + 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); + + gpg_err_set_errno (saved_errno); +} + + +/* 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; + int res; + + if (debug_level < level) + { + /* Disable logging of this line. */ + *line = NULL; + return; + } + + va_start (arg_ptr, format); + res = vasprintf ((char **) line, format, arg_ptr); + va_end (arg_ptr); + if (res < 0) + *line = NULL; +} + + +/* 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; + int res; + + if (!*line) + return; + + va_start (arg_ptr, format); + res = vasprintf (&toadd, format, arg_ptr); + va_end (arg_ptr); + if (res < 0) + { + free (*line); + *line = NULL; + } + res = asprintf (&result, "%s%s", *(char **) line, toadd); + free (toadd); + free (*line); + if (res < 0) + *line = NULL; + else + *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; +} + + +#define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a')) + +void +_gpgme_debug_buffer (int lvl, const char *const fmt, + const char *const func, const char *const buffer, + size_t len) +{ + int idx = 0; + int j; + + if (!_gpgme_debug_trace ()) + return; + + while (idx < len) + { + char str[51]; + char *strp = str; + char *strp2 = &str[34]; + + for (j = 0; j < 16; j++) + { + unsigned char val; + if (idx < len) + { + val = buffer[idx++]; + *(strp++) = TOHEX (val >> 4); + *(strp++) = TOHEX (val % 16); + *(strp2++) = isprint (val) ? val : '.'; + } + else + { + *(strp++) = ' '; + *(strp++) = ' '; + } + if (j == 7) + *(strp++) = ' '; + } + *(strp++) = ' '; + *(strp2) = '\0'; + + _gpgme_debug (lvl, fmt, func, str); + } +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..cbfccca --- /dev/null +++ b/src/debug.h @@ -0,0 +1,262 @@ +/* debug.h - interface to debugging functions + Copyright (C) 2002, 2004, 2005, 2007 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. */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include <string.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +/* Indirect stringification, requires __STDC__ to work. */ +#define STRINGIFY(v) #v +#define XSTRINGIFY(v) STRINGIFY(v) + + +/* The debug levels. */ + +#define DEBUG_INIT 1 +#define DEBUG_GLOBAL 2 +#define DEBUG_CTX 3 +#define DEBUG_ENGINE 4 +#define DEBUG_DATA 5 +#define DEBUG_ASSUAN 6 +#define DEBUG_SYSIO 7 + + +/* Remove path components from filenames (i.e. __FILE__) for cleaner + logs. */ +static inline const char *_gpgme_debug_srcname (const char *file) + GPGME_GCC_A_PURE; + +static inline const char * +_gpgme_debug_srcname (const char *file) +{ + const char *s = strrchr (file, '/'); + return s? s+1:file; +} + +/* Called early to initialize the logging. */ +void _gpgme_debug_subsystem_init (void); + +/* 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); + +void _gpgme_debug_buffer (int lvl, const char *const fmt, + const char *const func, const char *const buffer, + size_t len); + +void _gpgme_debug_frame_begin (void); +void _gpgme_debug_frame_end (void); + + + +/* Trace support. */ + +/* FIXME: For now. */ +#define _gpgme_debug_trace() 1 + +#define _TRACE(lvl, name, tag) \ + int _gpgme_trace_level = lvl; \ + const char *const _gpgme_trace_func = name; \ + const char *const _gpgme_trace_tagname = STRINGIFY (tag); \ + void *_gpgme_trace_tag = (void *) (uintptr_t) tag; \ + _gpgme_debug_frame_begin () + +#define TRACE_BEG(lvl, name, tag) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 +#define TRACE_BEG0(lvl, name, tag, fmt) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 +#define TRACE_BEG1(lvl, name, tag, fmt, arg1) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1), 0 +#define TRACE_BEG2(lvl, name, tag, fmt, arg1, arg2) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2), 0 +#define TRACE_BEG3(lvl, name, tag, fmt, arg1, arg2, arg3) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3), 0 +#define TRACE_BEG4(lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4), 0 +#define TRACE_BEG5(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4, arg5), 0 +#define TRACE_BEG7(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7), 0 +#define TRACE_BEG8(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ + arg5, arg6, arg7, arg8) \ + _TRACE (lvl, name, tag); \ + _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4, arg5, \ + arg6, arg7, arg8), 0 + +#define TRACE(lvl, name, tag) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ + _gpgme_debug_frame_end (), 0 +#define TRACE0(lvl, name, tag, fmt) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ + _gpgme_debug_frame_end (), 0 +#define TRACE1(lvl, name, tag, fmt, arg1) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1), \ + _gpgme_debug_frame_end (), 0 +#define TRACE2(lvl, name, tag, fmt, arg1, arg2) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2), _gpgme_debug_frame_end (), 0 +#define TRACE3(lvl, name, tag, fmt, arg1, arg2, arg3) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2, arg3), _gpgme_debug_frame_end (), 0 +#define TRACE6(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + _gpgme_debug_frame_begin (), \ + _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ + name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ + arg2, arg3, arg4, arg5, arg6), \ + _gpgme_debug_frame_end (), 0 + +#define TRACE_ERR(err) \ + err == 0 ? (TRACE_SUC ()) : \ + (_gpgme_debug (_gpgme_trace_level, "%s: error: %s <%s>\n", \ + _gpgme_trace_func, gpgme_strerror (err), \ + gpgme_strsource (err)), _gpgme_debug_frame_end (), (err)) +/* The cast to void suppresses GCC warnings. */ +#define TRACE_SYSRES(res) \ + res >= 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \ + (_gpgme_debug (_gpgme_trace_level, "%s: error: %s\n", \ + _gpgme_trace_func, strerror (errno)), _gpgme_debug_frame_end (), (res)) +#define TRACE_SYSERR(res) \ + res == 0 ? ((void) (TRACE_SUC1 ("result=%i", res)), (res)) : \ + (_gpgme_debug (_gpgme_trace_level, "%s: error: %s\n", \ + _gpgme_trace_func, strerror (res)), \ + _gpgme_debug_frame_end (), (res)) + +#define TRACE_SUC() \ + _gpgme_debug (_gpgme_trace_level, "%s: leave\n", \ + _gpgme_trace_func), _gpgme_debug_frame_end (), 0 +#define TRACE_SUC0(fmt) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func), _gpgme_debug_frame_end (), 0 +#define TRACE_SUC1(fmt, arg1) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func, arg1), _gpgme_debug_frame_end (), 0 +#define TRACE_SUC2(fmt, arg1, arg2) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func, arg1, arg2), _gpgme_debug_frame_end (), 0 +#define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \ + _gpgme_debug_frame_end (), 0 +#define TRACE_SUC6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ + _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5, arg6), \ + _gpgme_debug_frame_end (), 0 + +#define TRACE_LOG(fmt) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 +#define TRACE_LOG1(fmt, arg1) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1), 0 +#define TRACE_LOG2(fmt, arg1, arg2) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2), 0 +#define TRACE_LOG3(fmt, arg1, arg2, arg3) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3), 0 +#define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4), 0 +#define TRACE_LOG5(fmt, arg1, arg2, arg3, arg4, arg5) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4, arg5), 0 +#define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ + _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ + arg1, arg2, arg3, arg4, arg5, \ + arg6), 0 + +#define TRACE_LOGBUF(buf, len) \ + _gpgme_debug_buffer (_gpgme_trace_level, "%s: check: %s", \ + _gpgme_trace_func, buf, len) + +#define TRACE_SEQ(hlp,fmt) \ + _gpgme_debug_begin (&(hlp), _gpgme_trace_level, \ + "%s: check: %s=%p, " fmt, _gpgme_trace_func, \ + _gpgme_trace_tagname, _gpgme_trace_tag) +#define TRACE_ADD0(hlp,fmt) \ + _gpgme_debug_add (&(hlp), fmt) +#define TRACE_ADD1(hlp,fmt,a) \ + _gpgme_debug_add (&(hlp), fmt, (a)) +#define TRACE_ADD2(hlp,fmt,a,b) \ + _gpgme_debug_add (&(hlp), fmt, (a), (b)) +#define TRACE_ADD3(hlp,fmt,a,b,c) \ + _gpgme_debug_add (&(hlp), fmt, (a), (b), (c)) +#define TRACE_END(hlp,fmt) \ + _gpgme_debug_add (&(hlp), fmt); \ + _gpgme_debug_end (&(hlp)) +#define TRACE_ENABLED(hlp) (!!(hlp)) + +#endif /* DEBUG_H */ diff --git a/src/decrypt-verify.c b/src/decrypt-verify.c new file mode 100644 index 0000000..a5a751b --- /dev/null +++ b/src/decrypt-verify.c @@ -0,0 +1,121 @@ +/* decrypt-verify.c - Decrypt and verify 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include "debug.h" +#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_verify (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) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_verify_start", ctx, + "cipher=%p, plain=%p", cipher, plain); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = decrypt_verify_start (ctx, 0, cipher, plain); + return TRACE_ERR (err); +} + + +/* 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; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_verify", ctx, + "cipher=%p, plain=%p", cipher, plain); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = decrypt_verify_start (ctx, 1, cipher, plain); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/decrypt.c b/src/decrypt.c new file mode 100644 index 0000000..43945ec --- /dev/null +++ b/src/decrypt.c @@ -0,0 +1,403 @@ +/* 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "debug.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; + + /* A pointer to the next pointer of the last recipient in the list. + This makes appending new invalid signers painless while + preserving the order. */ + gpgme_recipient_t *last_recipient_p; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_recipient_t recipient = opd->result.recipients; + + if (opd->result.unsupported_algorithm) + free (opd->result.unsupported_algorithm); + + if (opd->result.file_name) + free (opd->result.file_name); + + while (recipient) + { + gpgme_recipient_t next = recipient->next; + free (recipient); + recipient = next; + } +} + + +gpgme_decrypt_result_t +gpgme_op_decrypt_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_decrypt_result", ctx); + + err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL); + opd = hook; + if (err || !opd) + { + TRACE_SUC0 ("result=(null)"); + return NULL; + } + + if (_gpgme_debug_trace ()) + { + gpgme_recipient_t rcp; + + if (opd->result.unsupported_algorithm) + { + TRACE_LOG1 ("result: unsupported_algorithm: %s", + opd->result.unsupported_algorithm); + } + if (opd->result.wrong_key_usage) + { + TRACE_LOG ("result: wrong key usage"); + } + rcp = opd->result.recipients; + while (rcp) + { + TRACE_LOG3 ("result: recipient: keyid=%s, pubkey_algo=%i, " + "status=%s", rcp->keyid, rcp->pubkey_algo, + gpg_strerror (rcp->status)); + rcp = rcp->next; + } + if (opd->result.file_name) + { + TRACE_LOG1 ("result: original file name: %s", opd->result.file_name); + } + } + + TRACE_SUC1 ("result=%p", &opd->result); + return &opd->result; +} + + +static gpgme_error_t +parse_enc_to (char *args, gpgme_recipient_t *recp) +{ + gpgme_recipient_t rec; + char *tail; + int i; + + rec = malloc (sizeof (*rec)); + if (!rec) + return gpg_error_from_syserror (); + + rec->next = NULL; + rec->keyid = rec->_keyid; + rec->status = 0; + + for (i = 0; i < sizeof (rec->_keyid) - 1; i++) + { + if (args[i] == '\0' || args[i] == ' ') + break; + + rec->_keyid[i] = args[i]; + } + rec->_keyid[i] = '\0'; + + args = &args[i]; + if (*args != '\0' && *args != ' ') + { + free (rec); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + while (*args == ' ') + args++; + + if (*args) + { + gpg_err_set_errno (0); + rec->pubkey_algo = strtol (args, &tail, 0); + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (rec); + return gpg_error (GPG_ERR_INV_ENGINE); + } + } + + /* FIXME: The key length is always 0 right now, so no need to parse + it. */ + + *recp = rec; + return 0; +} + + +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_INFO: + /* Fixme: Provide a way to return the used symmetric algorithm. */ + 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 k_alg[] = "decrypt.keyusage"; + + if (!strncmp (args, d_alg, sizeof (d_alg) - 1)) + { + args += sizeof (d_alg) - 1; + while (*args == ' ') + args++; + + if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM) + { + char *end; + + while (*args && *args != ' ') + args++; + 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_syserror (); + } + } + } + else if (!strncmp (args, k_alg, sizeof (k_alg) - 1)) + { + args += sizeof (k_alg) - 1; + while (*args == ' ') + args++; + + if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE) + opd->result.wrong_key_usage = 1; + } + } + break; + + case GPGME_STATUS_ENC_TO: + err = parse_enc_to (args, opd->last_recipient_p); + if (err) + return err; + + opd->last_recipient_p = &(*opd->last_recipient_p)->next; + break; + + case GPGME_STATUS_NO_SECKEY: + { + gpgme_recipient_t rec = opd->result.recipients; + + while (rec) + { + if (!strcmp (rec->keyid, args)) + { + rec->status = gpg_error (GPG_ERR_NO_SECKEY); + break; + } + rec = rec->next; + } + /* FIXME: Is this ok? */ + if (!rec) + return gpg_error (GPG_ERR_INV_ENGINE); + } + break; + + case GPGME_STATUS_PLAINTEXT: + err = _gpgme_parse_plaintext (args, &opd->result.file_name); + if (err) + return err; + + 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) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + opd->last_recipient_p = &opd->result.recipients; + return 0; +} + + +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) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt_start", ctx, + "cipher=%p, plain=%p", cipher, plain); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = decrypt_start (ctx, 0, cipher, plain); + return TRACE_ERR (err); +} + + +/* 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; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_decrypt", ctx, + "cipher=%p, plain=%p", cipher, plain); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = decrypt_start (ctx, 1, cipher, plain); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/delete.c b/src/delete.c new file mode 100644 index 0000000..1a501d8 --- /dev/null +++ b/src/delete.c @@ -0,0 +1,131 @@ +/* delete.c - Delete a key. + 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <errno.h> + +#include "debug.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; + + gpg_err_set_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) +{ + gpgme_error_t err; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete", ctx, + "key=%p (%s), allow_secret=%i", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", allow_secret); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = delete_start (ctx, 0, key, allow_secret); + return TRACE_ERR (err); +} + + +/* 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; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete", ctx, + "key=%p (%s), allow_secret=%i", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", allow_secret); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = delete_start (ctx, 1, key, allow_secret); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/src/dirinfo.c b/src/dirinfo.c new file mode 100644 index 0000000..b1e438e --- /dev/null +++ b/src/dirinfo.c @@ -0,0 +1,189 @@ +/* dirinfo.c - Get directory information + * Copyright (C) 2009 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, see <http://www.gnu.org/licenses/>. + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#include "gpgme.h" +#include "util.h" +#include "priv-io.h" +#include "debug.h" +#include "sema.h" + +DEFINE_STATIC_LOCK (dirinfo_lock); + +/* Constants used internally to select the data. */ +enum + { + WANT_HOMEDIR, + WANT_AGENT_SOCKET + }; + +/* Values retrieved via gpgconf and cached here. */ +static struct { + int valid; /* Cached information is valid. */ + char *homedir; + char *agent_socket; +} dirinfo; + + +/* Parse the output of "gpgconf --list-dirs". This function expects + that DIRINFO_LOCK is held by the caller. */ +static void +parse_output (char *line) +{ + char *value, *p; + + value = strchr (line, ':'); + if (!value) + return; + *value++ = 0; + p = strchr (value, ':'); + if (p) + *p = 0; + if (_gpgme_decode_percent_string (value, &value, strlen (value)+1, 0)) + return; + if (!*value) + return; + + if (!strcmp (line, "homedir") && !dirinfo.homedir) + dirinfo.homedir = strdup (value); + else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket) + dirinfo.agent_socket = strdup (value); +} + + +/* Read the directory information from gpgconf. This function expects + that DIRINFO_LOCK is held by the caller. */ +static void +read_gpgconf_dirs (void) +{ + const char *pgmname; + char linebuf[1024] = {0}; + int linelen = 0; + char * argv[3]; + int rp[2]; + struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0}, + {-1, -1} }; + int status; + int nread; + char *mark = NULL; + + pgmname = _gpgme_get_gpgconf_path (); + if (!pgmname) + return; /* No way. */ + + argv[0] = (char *)pgmname; + argv[1] = "--list-dirs"; + argv[2] = NULL; + + if (_gpgme_io_pipe (rp, 1) < 0) + return; + + cfd[0].fd = rp[1]; + + status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL, NULL, NULL); + if (status < 0) + { + _gpgme_io_close (rp[0]); + _gpgme_io_close (rp[1]); + return; + } + + do + { + nread = _gpgme_io_read (rp[0], + linebuf + linelen, + sizeof linebuf - linelen - 1); + if (nread > 0) + { + char *line; + const char *lastmark = NULL; + size_t nused; + + linelen += nread; + linebuf[linelen] = '\0'; + + for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 ) + { + lastmark = mark; + if (mark > line && mark[-1] == '\r') + mark[-1] = '\0'; + else + mark[0] = '\0'; + + parse_output (line); + } + + nused = lastmark? (lastmark + 1 - linebuf) : 0; + memmove (linebuf, linebuf + nused, linelen - nused); + linelen -= nused; + } + } + while (nread > 0 && linelen < sizeof linebuf - 1); + + _gpgme_io_close (rp[0]); +} + + +static const char * +get_gpgconf_dir (int what) +{ + const char *result = NULL; + + LOCK (dirinfo_lock); + if (!dirinfo.valid) + { + read_gpgconf_dirs (); + /* Even if the reading of the directories failed (e.g. due to an + too old version gpgconf or no gpgconf at all), we need to + mark the entries as valid so that we won't try over and over + to read them. Note further that we are not able to change + the read values later because they are practically statically + allocated. */ + dirinfo.valid = 1; + } + switch (what) + { + case WANT_HOMEDIR: result = dirinfo.homedir; break; + case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break; + } + UNLOCK (dirinfo_lock); + return result; +} + + +/* Return the default home directory. Returns NULL if not known. */ +const char * +_gpgme_get_default_homedir (void) +{ + return get_gpgconf_dir (WANT_HOMEDIR); +} + +/* Return the default gpg-agent socket name. Returns NULL if not known. */ +const char * +_gpgme_get_default_agent_socket (void) +{ + return get_gpgconf_dir (WANT_AGENT_SOCKET); +} + diff --git a/src/edit.c b/src/edit.c new file mode 100644 index 0000000..4abf24f --- /dev/null +++ b/src/edit.c @@ -0,0 +1,221 @@ +/* edit.c - Key edit function. + 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> + +#include "gpgme.h" +#include "debug.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, int *processed_r) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + int processed = 0; + + if (ctx->passphrase_cb) + { + err = _gpgme_passphrase_command_handler (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; + + /* FIXME: We expect the user to handle _all_ status codes. + Later, we may fix the callback interface to allow the user + indicate if it processed the status code or not. */ + *processed_r = 1; + + return (*opd->fnc) (opd->fnc_value, status, args, fd); + } + + *processed_r = processed; + 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) +{ + gpgme_error_t err; + + TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit_start", ctx, + "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", fnc, fnc_value, out); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = edit_start (ctx, 0, 0, key, fnc, fnc_value, out); + return err; +} + + +/* 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; + + TRACE_BEG5 (DEBUG_CTX, "gpgme_op_edit", ctx, + "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", fnc, fnc_value, out); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = edit_start (ctx, 1, 0, key, fnc, fnc_value, out); + + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (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) +{ + gpgme_error_t err; + + TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit_start", ctx, + "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", fnc, fnc_value, out); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = edit_start (ctx, 0, 1, key, fnc, fnc_value, out); + return err; +} + + +/* 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; + + TRACE_BEG5 (DEBUG_CTX, "gpgme_op_card_edit", ctx, + "key=%p (%s), fnc=%p fnc_value=%p, out=%p", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", fnc, fnc_value, out); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = edit_start (ctx, 1, 1, key, fnc, fnc_value, out); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/encrypt-sign.c b/src/encrypt-sign.c new file mode 100644 index 0000000..7828600 --- /dev/null +++ b/src/encrypt-sign.c @@ -0,0 +1,157 @@ +/* encrypt-sign.c - encrypt and verify functions + 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "gpgme.h" +#include "debug.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) +{ + gpgme_error_t err; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign_start", ctx, + "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + + err = encrypt_sign_start (ctx, 0, recp, flags, plain, cipher); + return err; +} + + +/* 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; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_sign", ctx, + "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + + err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/encrypt.c b/src/encrypt.c new file mode 100644 index 0000000..641e900 --- /dev/null +++ b/src/encrypt.c @@ -0,0 +1,288 @@ +/* encrypt.c - Encrypt 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 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "gpgme.h" +#include "debug.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); + free (invalid_recipient); + 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; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_encrypt_result", ctx); + + err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL); + opd = hook; + + if (err || !opd) + { + TRACE_SUC0 ("result=(null)"); + return NULL; + } + + if (_gpgme_debug_trace ()) + { + gpgme_invalid_key_t invkeys = opd->result.invalid_recipients; + int i = 0; + + while (invkeys) + { + TRACE_LOG3 ("invalid_recipients[%i] = %s (%s)", + i, invkeys->fpr ? invkeys->fpr : "(null)", + gpg_strerror (invkeys->reason)); + invkeys = invkeys->next; + i++; + } + } + + TRACE_SUC1 ("result=%p", &opd->result); + 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) +{ + gpgme_error_t err; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt_start", ctx, + "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + + err = encrypt_start (ctx, 0, recp, flags, plain, cipher); + return TRACE_ERR (err); +} + + +/* 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; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_encrypt", ctx, + "flags=0x%x, plain=%p, cipher=%p", flags, plain, cipher); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && recp) + { + int i = 0; + + while (recp[i]) + { + TRACE_LOG3 ("recipient[%i] = %p (%s)", i, recp[i], + (recp[i]->subkeys && recp[i]->subkeys->fpr) ? + recp[i]->subkeys->fpr : "invalid"); + i++; + } + } + + err = encrypt_start (ctx, 1, recp, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} diff --git a/src/engine-assuan.c b/src/engine-assuan.c new file mode 100644 index 0000000..dedb8a1 --- /dev/null +++ b/src/engine-assuan.c @@ -0,0 +1,785 @@ +/* engine-assuan.c - Low-level Assuan protocol engine + * Copyright (C) 2009 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, see <http://www.gnu.org/licenses/>. + */ + +/* + Note: This engine requires a modern Assuan server which uses + gpg-error codes. In particular there is no backward compatible + mapping of old Assuan error codes implemented. +*/ + + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#include <assert.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "priv-io.h" +#include "sema.h" + +#include "assuan.h" +#include "debug.h" + +#include "engine-backend.h" + + +typedef struct +{ + int fd; /* FD we talk about. */ + int server_fd;/* Server FD for this connection. */ + 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; + +/* Engine instance data. */ +struct engine_llass +{ + assuan_context_t assuan_ctx; + + int lc_ctype_set; + int lc_messages_set; + + iocb_data_t status_cb; + + struct gpgme_io_cbs io_cbs; + + /* Hack for old opassuan.c interface, see there the result struct. */ + gpg_error_t last_op_err; + + /* User provided callbacks. */ + struct { + gpgme_assuan_data_cb_t data_cb; + void *data_cb_value; + + gpgme_assuan_inquire_cb_t inq_cb; + void *inq_cb_value; + + gpgme_assuan_status_cb_t status_cb; + void *status_cb_value; + } user; + + /* Option flags. */ + struct { + int gpg_agent:1; /* Assume this is a gpg-agent connection. */ + } opt; + +}; +typedef struct engine_llass *engine_llass_t; + + +gpg_error_t _gpgme_engine_assuan_last_op_err (void *engine) +{ + engine_llass_t llass = engine; + return llass->last_op_err; +} + + +/* Prototypes. */ +static void llass_io_event (void *engine, + gpgme_event_io_t type, void *type_data); + + + + + +/* return the default home directory. */ +static const char * +llass_get_home_dir (void) +{ + /* For this engine the home directory is not a filename but a string + used to convey options. The exclamation mark is a marker to show + that this is not a directory name. Options are strings delimited + by a space. The only option defined for now is GPG_AGENT to + enable GPG_AGENT specific commands to send to the server at + connection startup. */ + return "!GPG_AGENT"; +} + +static char * +llass_get_version (const char *file_name) +{ + return strdup ("1.0"); +} + + +static const char * +llass_get_req_version (void) +{ + return "1.0"; +} + + +static void +close_notify_handler (int fd, void *opaque) +{ + engine_llass_t llass = opaque; + + assert (fd != -1); + if (llass->status_cb.fd == fd) + { + if (llass->status_cb.tag) + llass->io_cbs.remove (llass->status_cb.tag); + llass->status_cb.fd = -1; + llass->status_cb.tag = NULL; + } +} + + + +static gpgme_error_t +llass_cancel (void *engine) +{ + engine_llass_t llass = engine; + + if (!llass) + return gpg_error (GPG_ERR_INV_VALUE); + + if (llass->status_cb.fd != -1) + _gpgme_io_close (llass->status_cb.fd); + + if (llass->assuan_ctx) + { + assuan_release (llass->assuan_ctx); + llass->assuan_ctx = NULL; + } + + return 0; +} + + +static gpgme_error_t +llass_cancel_op (void *engine) +{ + engine_llass_t llass = engine; + + if (!llass) + return gpg_error (GPG_ERR_INV_VALUE); + + if (llass->status_cb.fd != -1) + _gpgme_io_close (llass->status_cb.fd); + + return 0; +} + + +static void +llass_release (void *engine) +{ + engine_llass_t llass = engine; + + if (!llass) + return; + + llass_cancel (engine); + + free (llass); +} + + +/* Create a new instance. If HOME_DIR is NULL standard options for use + with gpg-agent are issued. */ +static gpgme_error_t +llass_new (void **engine, const char *file_name, const char *home_dir) +{ + gpgme_error_t err = 0; + engine_llass_t llass; + char *optstr; + + llass = calloc (1, sizeof *llass); + if (!llass) + return gpg_error_from_syserror (); + + llass->status_cb.fd = -1; + llass->status_cb.dir = 1; + llass->status_cb.tag = 0; + llass->status_cb.data = llass; + + /* Parse_options. */ + if (home_dir && *home_dir == '!') + { + home_dir++; + /* Very simple parser only working for the one option we support. */ + /* Note that wk promised to write a regression test if this + parser will be extended. */ + if (!strncmp (home_dir, "GPG_AGENT", 9) + && (!home_dir[9] || home_dir[9] == ' ')) + llass->opt.gpg_agent = 1; + } + + err = assuan_new_ext (&llass->assuan_ctx, GPG_ERR_SOURCE_GPGME, + &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb, + NULL); + if (err) + goto leave; + assuan_ctx_set_system_hooks (llass->assuan_ctx, &_gpgme_assuan_system_hooks); + + err = assuan_socket_connect (llass->assuan_ctx, file_name, 0, 0); + if (err) + goto leave; + + if (llass->opt.gpg_agent) + { + char *dft_display = NULL; + + err = _gpgme_getenv ("DISPLAY", &dft_display); + if (err) + goto leave; + if (dft_display) + { + if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0) + { + err = gpg_error_from_syserror (); + free (dft_display); + goto leave; + } + free (dft_display); + + err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (err) + goto leave; + } + } + + if (llass->opt.gpg_agent && isatty (1)) + { + int rc; + char dft_ttyname[64]; + char *dft_ttytype = NULL; + + rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); + if (rc) + { + err = gpg_error_from_errno (rc); + goto leave; + } + else + { + if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (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) + { + err = gpg_error_from_syserror (); + free (dft_ttytype); + goto leave; + } + free (dft_ttytype); + + err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + if (err) + goto leave; + } + } + } + + +#ifdef HAVE_W32_SYSTEM + /* Under Windows we need to use AllowSetForegroundWindow. Tell + llass to tell us when it needs it. */ + if (!err && llass->opt.gpg_agent) + { + err = assuan_transact (llass->assuan_ctx, "OPTION allow-pinentry-notify", + NULL, NULL, NULL, NULL, NULL, NULL); + if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) + err = 0; /* This work only with recent gpg-agents. */ + } +#endif /*HAVE_W32_SYSTEM*/ + + + leave: + /* Close the server ends of the pipes (because of this, we must use + the stored server_fd_str in the function start). Our ends are + closed in llass_release(). */ + + if (err) + llass_release (llass); + else + *engine = llass; + + return err; +} + + +static gpgme_error_t +llass_set_locale (void *engine, int category, const char *value) +{ + gpgme_error_t err; + engine_llass_t llass = engine; + char *optstr; + char *catstr; + + if (!llass->opt.gpg_agent) + return 0; + + /* FIXME: If value is NULL, we need to reset the option to default. + But we can't do this. So we error out here. gpg-agent needs + support for this. */ + if (0) + ; +#ifdef LC_CTYPE + else if (category == LC_CTYPE) + { + catstr = "lc-ctype"; + if (!value && llass->lc_ctype_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + llass->lc_ctype_set = 1; + } +#endif +#ifdef LC_MESSAGES + else if (category == LC_MESSAGES) + { + catstr = "lc-messages"; + if (!value && llass->lc_messages_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + llass->lc_messages_set = 1; + } +#endif /* LC_MESSAGES */ + else + return gpg_error (GPG_ERR_INV_VALUE); + + /* FIXME: Reset value to default. */ + if (!value) + return 0; + + if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0) + err = gpg_error_from_errno (errno); + else + { + err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + } + return err; +} + + +/* This is the inquiry callback. It handles stuff which ee need to + handle here and passes everything on to the user callback. */ +static gpgme_error_t +inquire_cb (engine_llass_t llass, const char *keyword, const char *args) +{ + gpg_error_t err; + + if (llass->opt.gpg_agent && !strcmp (keyword, "PINENTRY_LAUNCHED")) + { + _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10)); + } + + if (llass->user.inq_cb) + { + gpgme_data_t data = NULL; + + err = llass->user.inq_cb (llass->user.inq_cb_value, + keyword, args, &data); + if (!err && data) + { + /* FIXME: Returning data is not yet implemented. However we + need to allow the caller to cleanup his data object. + Thus we run the callback in finish mode immediately. */ + err = llass->user.inq_cb (llass->user.inq_cb_value, + NULL, NULL, &data); + } + } + else + err = 0; + + return err; +} + + +static gpgme_error_t +llass_status_handler (void *opaque, int fd) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + engine_llass_t llass = (engine_llass_t) data->handler_value; + gpgme_error_t err = 0; + char *line; + size_t linelen; + + do + { + err = assuan_read_line (llass->assuan_ctx, &line, &linelen); + if (err) + { + /* Reading a full line may not be possible when + communicating over a socket in nonblocking mode. In this + case, we are done for now. */ + if (gpg_err_code (err) == GPG_ERR_EAGAIN) + { + TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: EAGAIN reading assuan line (ignored)", fd); + err = 0; + continue; + } + + TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: error reading assuan line: %s", + fd, gpg_strerror (err)); + } + else if (linelen >= 2 && line[0] == 'D' && line[1] == ' ') + { + char *src = line + 2; + char *end = line + linelen; + char *dst = src; + + linelen = 0; + while (src < end) + { + if (*src == '%' && src + 2 < end) + { + /* Handle escaped characters. */ + ++src; + *dst++ = _gpgme_hextobyte (src); + src += 2; + } + else + *dst++ = *src++; + + linelen++; + } + + src = line + 2; + if (linelen && llass->user.data_cb) + err = llass->user.data_cb (llass->user.data_cb_value, + src, linelen); + + TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: D inlinedata; status from cb: %s", + fd, (llass->user.data_cb ? + (err? gpg_strerror (err):"ok"):"no callback")); + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (line[3] == '\0' || line[3] == ' ')) + { + /* END received. Tell the data callback. */ + if (llass->user.data_cb) + err = llass->user.data_cb (llass->user.data_cb_value, NULL, 0); + + TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: END line; status from cb: %s", + fd, (llass->user.data_cb ? + (err? gpg_strerror (err):"ok"):"no callback")); + } + else if (linelen > 2 && line[0] == 'S' && line[1] == ' ') + { + char *args; + char *src; + + for (src=line+2; *src == ' '; src++) + ; + + args = strchr (src, ' '); + if (!args) + args = line + linelen; /* Let it point to an empty string. */ + else + *(args++) = 0; + + while (*args == ' ') + args++; + + if (llass->user.status_cb) + err = llass->user.status_cb (llass->user.status_cb_value, + src, args); + + TRACE3 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: S line (%s) - status from cb: %s", + fd, line+2, (llass->user.status_cb ? + (err? gpg_strerror (err):"ok"):"no callback")); + } + else if (linelen >= 7 + && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' + && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' + && line[6] == 'E' + && (line[7] == '\0' || line[7] == ' ')) + { + char *src; + char *args; + + for (src=line+7; *src == ' '; src++) + ; + + args = strchr (src, ' '); + if (!args) + args = line + linelen; /* Let it point to an empty string. */ + else + *(args++) = 0; + + while (*args == ' ') + args++; + + err = inquire_cb (llass, src, args); + if (!err) + { + /* Flush and send END. */ + err = assuan_send_data (llass->assuan_ctx, NULL, 0); + } + else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED) + { + /* Flush and send CANcel. */ + err = assuan_send_data (llass->assuan_ctx, NULL, 1); + } + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + if (line[3] == ' ') + err = atoi (line+4); + else + err = gpg_error (GPG_ERR_GENERAL); + TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: ERR line: %s", + fd, err ? gpg_strerror (err) : "ok"); + + /* Command execution errors are not fatal, as we use + a session based protocol. */ + data->op_err = err; + llass->last_op_err = err; + + /* The caller will do the rest (namely, call cancel_op, + which closes status_fd). */ + return 0; + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass, + "fd 0x%x: OK line", fd); + + llass->last_op_err = 0; + + _gpgme_io_close (llass->status_cb.fd); + return 0; + } + else + { + /* Comment line or invalid line. */ + } + + } + while (!err && assuan_pending_line (llass->assuan_ctx)); + + return err; +} + + +static gpgme_error_t +add_io_cb (engine_llass_t llass, iocb_data_t *iocbd, gpgme_io_cb_t handler) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_ENGINE, "engine-assuan:add_io_cb", llass, + "fd %d, dir %d", iocbd->fd, iocbd->dir); + err = (*llass->io_cbs.add) (llass->io_cbs.add_priv, + iocbd->fd, iocbd->dir, + handler, iocbd->data, &iocbd->tag); + if (err) + return TRACE_ERR (err); + if (!iocbd->dir) + /* FIXME Kludge around poll() problem. */ + err = _gpgme_io_set_nonblocking (iocbd->fd); + return TRACE_ERR (err); +} + + +static gpgme_error_t +start (engine_llass_t llass, const char *command) +{ + gpgme_error_t err; + assuan_fd_t afdlist[5]; + int fdlist[5]; + int nfds; + int i; + + /* 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 (llass->assuan_ctx, 0 /* read fds */, + afdlist, DIM (afdlist)); + if (nfds < 1) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + /* For now... */ + for (i = 0; i < nfds; i++) + fdlist[i] = (int) afdlist[i]; + + /* We "duplicate" the file descriptor, so we can close it here (we + can't close fdlist[0], as that is closed by libassuan, and + closing it here might cause libassuan to close some unrelated FD + later). 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. A third alternative would be to let + Assuan know that we closed the FD, but that complicates the + Assuan interface. */ + + llass->status_cb.fd = _gpgme_io_dup (fdlist[0]); + if (llass->status_cb.fd < 0) + return gpg_error_from_syserror (); + + if (_gpgme_io_set_close_notify (llass->status_cb.fd, + close_notify_handler, llass)) + { + _gpgme_io_close (llass->status_cb.fd); + llass->status_cb.fd = -1; + return gpg_error (GPG_ERR_GENERAL); + } + + err = add_io_cb (llass, &llass->status_cb, llass_status_handler); + if (!err) + err = assuan_write_line (llass->assuan_ctx, command); + + /* FIXME: If *command == '#' no answer is expected. */ + + if (!err) + llass_io_event (llass, GPGME_EVENT_START, NULL); + + return err; +} + + + +static gpgme_error_t +llass_transact (void *engine, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value) +{ + engine_llass_t llass = engine; + gpgme_error_t err; + + if (!llass || !command || !*command) + return gpg_error (GPG_ERR_INV_VALUE); + + llass->user.data_cb = data_cb; + llass->user.data_cb_value = data_cb_value; + llass->user.inq_cb = inq_cb; + llass->user.inq_cb_value = inq_cb_value; + llass->user.status_cb = status_cb; + llass->user.status_cb_value = status_cb_value; + + err = start (llass, command); + return err; +} + + + +static void +llass_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs) +{ + engine_llass_t llass = engine; + llass->io_cbs = *io_cbs; +} + + +static void +llass_io_event (void *engine, gpgme_event_io_t type, void *type_data) +{ + engine_llass_t llass = engine; + + TRACE3 (DEBUG_ENGINE, "gpgme:llass_io_event", llass, + "event %p, type %d, type_data %p", + llass->io_cbs.event, type, type_data); + if (llass->io_cbs.event) + (*llass->io_cbs.event) (llass->io_cbs.event_priv, type, type_data); +} + + +struct engine_ops _gpgme_engine_ops_assuan = + { + /* Static functions. */ + _gpgme_get_default_agent_socket, + llass_get_home_dir, + llass_get_version, + llass_get_req_version, + llass_new, + + /* Member functions. */ + llass_release, + NULL, /* reset */ + NULL, /* set_status_handler */ + NULL, /* set_command_handler */ + NULL, /* set_colon_line_handler */ + llass_set_locale, + NULL, /* set_protocol */ + NULL, /* decrypt */ + NULL, /* decrypt_verify */ + NULL, /* delete */ + NULL, /* edit */ + NULL, /* encrypt */ + NULL, /* encrypt_sign */ + NULL, /* export */ + NULL, /* export_ext */ + NULL, /* genkey */ + NULL, /* import */ + NULL, /* keylist */ + NULL, /* keylist_ext */ + NULL, /* sign */ + NULL, /* trustlist */ + NULL, /* verify */ + NULL, /* getauditlog */ + llass_transact, /* opassuan_transact */ + NULL, /* conf_load */ + NULL, /* conf_save */ + llass_set_io_cbs, + llass_io_event, + llass_cancel, + llass_cancel_op + }; diff --git a/src/engine-backend.h b/src/engine-backend.h new file mode 100644 index 0000000..e540acb --- /dev/null +++ b/src/engine-backend.h @@ -0,0 +1,144 @@ +/* engine-backend.h - A crypto backend for the engine interface. + Copyright (C) 2002, 2003, 2004, 2009 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef ENGINE_BACKEND_H +#define ENGINE_BACKEND_H + +#include "engine.h" + +struct engine_ops +{ + /* Static functions. */ + + /* Return the default file name for the binary of this engine. */ + const char *(*get_file_name) (void); + + /* Return the default home dir for the binary of this engine. If + this function pointer is not set, the standard default home dir + of the engine is used. */ + const char *(*get_home_dir) (void); + + /* Returns a malloced string containing the version of the engine + with the given binary file name (or the default if FILE_NAME is + NULL. */ + char *(*get_version) (const char *file_name); + + /* Returns a statically allocated string containing the required + version. */ + const char *(*get_req_version) (void); + + gpgme_error_t (*new) (void **r_engine, + const char *file_name, const char *home_dir); + + /* Member functions. */ + void (*release) (void *engine); + gpgme_error_t (*reset) (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 (*set_locale) (void *engine, int category, const char *value); + gpgme_error_t (*set_protocol) (void *engine, gpgme_protocol_t protocol); + gpgme_error_t (*decrypt) (void *engine, gpgme_data_t ciph, + gpgme_data_t plain); + gpgme_error_t (*decrypt_verify) (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, + gpgme_export_mode_t mode, gpgme_data_t keydata, + int use_armor); + gpgme_error_t (*export_ext) (void *engine, const char *pattern[], + gpgme_export_mode_t mode, 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_key_t *keyarray); + 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); + gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output, + unsigned int flags); + gpgme_error_t (*opassuan_transact) (void *engine, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value); + + gpgme_error_t (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p); + gpgme_error_t (*conf_save) (void *engine, gpgme_conf_comp_t conf); + + 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); + + /* Cancel the whole engine session. */ + gpgme_error_t (*cancel) (void *engine); + + /* Cancel only the current operation, not the whole session. */ + gpgme_error_t (*cancel_op) (void *engine); + + /* Change the passphrase for KEY. */ + gpgme_error_t (*passwd) (void *engine, gpgme_key_t key, unsigned int flags); +}; + + +extern struct engine_ops _gpgme_engine_ops_gpg; /* OpenPGP. */ +#ifdef ENABLE_GPGSM +extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */ +#endif +#ifdef ENABLE_GPGCONF +extern struct engine_ops _gpgme_engine_ops_gpgconf; /* gpg-conf. */ +#endif +#ifdef ENABLE_ASSUAN +extern struct engine_ops _gpgme_engine_ops_assuan; /* Low-level Assuan. */ +#endif +#ifdef ENABLE_G13 +extern struct engine_ops _gpgme_engine_ops_g13; /* Crypto VFS. */ +#endif +#ifdef ENABLE_UISERVER +extern struct engine_ops _gpgme_engine_ops_uiserver; +#endif + +#endif /* ENGINE_BACKEND_H */ diff --git a/src/engine-g13.c b/src/engine-g13.c new file mode 100644 index 0000000..6ba49c4 --- /dev/null +++ b/src/engine-g13.c @@ -0,0 +1,801 @@ +/* engine-g13.c - G13 engine. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#include <assert.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif +#include <fcntl.h> /* FIXME */ +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "priv-io.h" +#include "sema.h" + +#include "assuan.h" +#include "debug.h" + +#include "engine-backend.h" + + +typedef struct +{ + int fd; /* FD we talk about. */ + int server_fd;/* Server FD for this connection. */ + int dir; /* Inbound/Outbound, maybe given implicit? */ + void *data; /* Handler-specific data. */ + void *tag; /* ID from the user for gpgme_remove_io_callback. */ + char server_fd_str[15]; /* Same as SERVER_FD but as a string. We + need this because _gpgme_io_fd2str can't + be used on a closed descriptor. */ +} iocb_data_t; + + +struct engine_g13 +{ + assuan_context_t assuan_ctx; + + int lc_ctype_set; + int lc_messages_set; + + iocb_data_t status_cb; + + struct gpgme_io_cbs io_cbs; + + /* User provided callbacks. */ + struct { + gpgme_assuan_data_cb_t data_cb; + void *data_cb_value; + + gpgme_assuan_inquire_cb_t inq_cb; + void *inq_cb_value; + + gpgme_assuan_status_cb_t status_cb; + void *status_cb_value; + } user; +}; + +typedef struct engine_g13 *engine_g13_t; + + +static void g13_io_event (void *engine, + gpgme_event_io_t type, void *type_data); + + + +static char * +g13_get_version (const char *file_name) +{ + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_g13_path ()); +} + + +static const char * +g13_get_req_version (void) +{ + return NEED_G13_VERSION; +} + + +static void +close_notify_handler (int fd, void *opaque) +{ + engine_g13_t g13 = opaque; + + assert (fd != -1); + if (g13->status_cb.fd == fd) + { + if (g13->status_cb.tag) + (*g13->io_cbs.remove) (g13->status_cb.tag); + g13->status_cb.fd = -1; + g13->status_cb.tag = NULL; + } +} + + +/* This is the default inquiry callback. We use it to handle the + Pinentry notifications. */ +static gpgme_error_t +default_inq_cb (engine_g13_t g13, const char *keyword, const char *args) +{ + gpg_error_t err; + + if (!strcmp (keyword, "PINENTRY_LAUNCHED")) + { + _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10)); + } + + if (g13->user.inq_cb) + { + gpgme_data_t data = NULL; + + err = g13->user.inq_cb (g13->user.inq_cb_value, + keyword, args, &data); + if (!err && data) + { + /* FIXME: Returning data is not yet implemented. However we + need to allow the caller to cleanup his data object. + Thus we run the callback in finish mode immediately. */ + err = g13->user.inq_cb (g13->user.inq_cb_value, + NULL, NULL, &data); + } + } + else + err = 0; + + return err; +} + + +static gpgme_error_t +g13_cancel (void *engine) +{ + engine_g13_t g13 = engine; + + if (!g13) + return gpg_error (GPG_ERR_INV_VALUE); + + if (g13->status_cb.fd != -1) + _gpgme_io_close (g13->status_cb.fd); + + if (g13->assuan_ctx) + { + assuan_release (g13->assuan_ctx); + g13->assuan_ctx = NULL; + } + + return 0; +} + + +static gpgme_error_t +g13_cancel_op (void *engine) +{ + engine_g13_t g13 = engine; + + if (!g13) + return gpg_error (GPG_ERR_INV_VALUE); + + if (g13->status_cb.fd != -1) + _gpgme_io_close (g13->status_cb.fd); + + return 0; +} + + +static void +g13_release (void *engine) +{ + engine_g13_t g13 = engine; + + if (!g13) + return; + + g13_cancel (engine); + + free (g13); +} + + +static gpgme_error_t +g13_new (void **engine, const char *file_name, const char *home_dir) +{ + gpgme_error_t err = 0; + engine_g13_t g13; + int argc; + const char *argv[5]; + char *dft_display = NULL; + char dft_ttyname[64]; + char *dft_ttytype = NULL; + char *optstr; + + g13 = calloc (1, sizeof *g13); + if (!g13) + return gpg_error_from_errno (errno); + + g13->status_cb.fd = -1; + g13->status_cb.dir = 1; + g13->status_cb.tag = 0; + g13->status_cb.data = g13; + + argc = 0; + argv[argc++] = "g13"; + if (home_dir) + { + argv[argc++] = "--homedir"; + argv[argc++] = home_dir; + } + argv[argc++] = "--server"; + argv[argc++] = NULL; + + err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME, + &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb, + NULL); + if (err) + goto leave; + assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks); + +#if USE_DESCRIPTOR_PASSING + err = assuan_pipe_connect + (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (), + argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING); +#else + err = assuan_pipe_connect + (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (), + argv, NULL, NULL, NULL, 0); +#endif + if (err) + goto leave; + + 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 (g13->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (err) + goto leave; + } + + if (isatty (1)) + { + int rc; + + rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); + if (rc) + { + err = gpg_error_from_errno (rc); + goto leave; + } + else + { + if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) + { + err = gpg_error_from_errno (errno); + goto leave; + } + err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (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 (g13->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + if (err) + goto leave; + } + } + } + +#ifdef HAVE_W32_SYSTEM + /* Under Windows we need to use AllowSetForegroundWindow. Tell + g13 to tell us when it needs it. */ + if (!err) + { + err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify", + NULL, NULL, NULL, NULL, NULL, NULL); + if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) + err = 0; /* This is a new feature of g13. */ + } +#endif /*HAVE_W32_SYSTEM*/ + + leave: + + if (err) + g13_release (g13); + else + *engine = g13; + + return err; +} + + +static gpgme_error_t +g13_set_locale (void *engine, int category, const char *value) +{ + engine_g13_t g13 = engine; + gpgme_error_t err; + char *optstr; + char *catstr; + + /* FIXME: If value is NULL, we need to reset the option to default. + But we can't do this. So we error out here. G13 needs support + for this. */ + if (0) + ; +#ifdef LC_CTYPE + else if (category == LC_CTYPE) + { + catstr = "lc-ctype"; + if (!value && g13->lc_ctype_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + g13->lc_ctype_set = 1; + } +#endif +#ifdef LC_MESSAGES + else if (category == LC_MESSAGES) + { + catstr = "lc-messages"; + if (!value && g13->lc_messages_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + g13->lc_messages_set = 1; + } +#endif /* LC_MESSAGES */ + else + return gpg_error (GPG_ERR_INV_VALUE); + + /* FIXME: Reset value to default. */ + if (!value) + return 0; + + if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0) + err = gpg_error_from_errno (errno); + else + { + err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + } + + return err; +} + + +#if USE_DESCRIPTOR_PASSING +static gpgme_error_t +g13_assuan_simple_command (assuan_context_t ctx, char *cmd, + engine_status_handler_t status_fnc, + void *status_fnc_value) +{ + gpg_error_t err; + char *line; + size_t linelen; + + err = assuan_write_line (ctx, cmd); + if (err) + return err; + + do + { + err = assuan_read_line (ctx, &line, &linelen); + if (err) + return 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 = atoi (&line[4]); + else if (linelen >= 2 + && line[0] == 'S' && line[1] == ' ') + { + char *rest; + + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; + + /* Nothing to do with status lines. */ + } + else + err = gpg_error (GPG_ERR_GENERAL); + } + while (!err); + + return err; +} +#endif + + +static gpgme_error_t +status_handler (void *opaque, int fd) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + engine_g13_t g13 = (engine_g13_t) data->handler_value; + gpgme_error_t err = 0; + char *line; + size_t linelen; + + do + { + err = assuan_read_line (g13->assuan_ctx, &line, &linelen); + if (err) + { + /* Try our best to terminate the connection friendly. */ + /* assuan_write_line (g13->assuan_ctx, "BYE"); */ + TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13, + "fd 0x%x: error reading assuan line: %s", + fd, 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 = atoi (&line[4]); + if (! err) + err = gpg_error (GPG_ERR_GENERAL); + TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13, + "fd 0x%x: ERR line: %s", + fd, err ? gpg_strerror (err) : "ok"); + + /* Command execution errors are not fatal, as we use + a session based protocol. */ + data->op_err = err; + + /* The caller will do the rest (namely, call cancel_op, + which closes status_fd). */ + return 0; + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13, + "fd 0x%x: OK line", fd); + + _gpgme_io_close (g13->status_cb.fd); + return 0; + } + else if (linelen > 2 + && line[0] == 'D' && line[1] == ' ') + { + /* 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. */ + char *src = line + 2; + char *end = line + linelen; + char *dst = src; + + linelen = 0; + while (src < end) + { + if (*src == '%' && src + 2 < end) + { + /* Handle escaped characters. */ + ++src; + *dst++ = _gpgme_hextobyte (src); + src += 2; + } + else + *dst++ = *src++; + + linelen++; + } + + src = line + 2; + if (linelen && g13->user.data_cb) + err = g13->user.data_cb (g13->user.data_cb_value, + src, linelen); + else + err = 0; + + TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13, + "fd 0x%x: D inlinedata; status from cb: %s", + fd, (g13->user.data_cb ? + (err? gpg_strerror (err):"ok"):"no callback")); + + } + else if (linelen > 2 + && line[0] == 'S' && line[1] == ' ') + { + char *src; + char *args; + + src = line + 2; + while (*src == ' ') + src++; + + args = strchr (line + 2, ' '); + if (!args) + args = line + linelen; /* set to an empty string */ + else + *(args++) = 0; + + while (*args == ' ') + args++; + + if (g13->user.status_cb) + err = g13->user.status_cb (g13->user.status_cb_value, + src, args); + else + err = 0; + + TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13, + "fd 0x%x: S line (%s) - status from cb: %s", + fd, line+2, (g13->user.status_cb ? + (err? gpg_strerror (err):"ok"):"no callback")); + } + else if (linelen >= 7 + && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' + && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' + && line[6] == 'E' + && (line[7] == '\0' || line[7] == ' ')) + { + char *src; + char *args; + + for (src=line+7; *src == ' '; src++) + ; + + args = strchr (src, ' '); + if (!args) + args = line + linelen; /* Let it point to an empty string. */ + else + *(args++) = 0; + + while (*args == ' ') + args++; + + err = default_inq_cb (g13, src, args); + if (!err) + { + /* Flush and send END. */ + err = assuan_send_data (g13->assuan_ctx, NULL, 0); + } + else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED) + { + /* Flush and send CANcel. */ + err = assuan_send_data (g13->assuan_ctx, NULL, 1); + } + assuan_write_line (g13->assuan_ctx, "END"); + } + } + while (!err && assuan_pending_line (g13->assuan_ctx)); + + return err; +} + + +static gpgme_error_t +add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_ENGINE, "engine-g13:add_io_cb", g13, + "fd %d, dir %d", iocbd->fd, iocbd->dir); + err = (*g13->io_cbs.add) (g13->io_cbs.add_priv, + iocbd->fd, iocbd->dir, + handler, iocbd->data, &iocbd->tag); + if (err) + return TRACE_ERR (err); + if (!iocbd->dir) + /* FIXME Kludge around poll() problem. */ + err = _gpgme_io_set_nonblocking (iocbd->fd); + return TRACE_ERR (err); +} + + +static gpgme_error_t +start (engine_g13_t g13, const char *command) +{ + gpgme_error_t err; + assuan_fd_t afdlist[5]; + int fdlist[5]; + int nfds; + int i; + + /* 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 (g13->assuan_ctx, 0 /* read fds */, + afdlist, DIM (afdlist)); + if (nfds < 1) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + /* For now... */ + for (i = 0; i < nfds; i++) + fdlist[i] = (int) afdlist[i]; + + /* We "duplicate" the file descriptor, so we can close it here (we + can't close fdlist[0], as that is closed by libassuan, and + closing it here might cause libassuan to close some unrelated FD + later). 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. A third alternative would be to let + Assuan know that we closed the FD, but that complicates the + Assuan interface. */ + + g13->status_cb.fd = _gpgme_io_dup (fdlist[0]); + if (g13->status_cb.fd < 0) + return gpg_error_from_syserror (); + + if (_gpgme_io_set_close_notify (g13->status_cb.fd, + close_notify_handler, g13)) + { + _gpgme_io_close (g13->status_cb.fd); + g13->status_cb.fd = -1; + return gpg_error (GPG_ERR_GENERAL); + } + + err = add_io_cb (g13, &g13->status_cb, status_handler); + if (!err) + err = assuan_write_line (g13->assuan_ctx, command); + + if (!err) + g13_io_event (g13, GPGME_EVENT_START, NULL); + + return err; +} + + +#if USE_DESCRIPTOR_PASSING +static gpgme_error_t +g13_reset (void *engine) +{ + engine_g13_t g13 = engine; + + /* We must send a reset because we need to reset the list of + signers. Note that RESET does not reset OPTION commands. */ + return g13_assuan_simple_command (g13->assuan_ctx, "RESET", NULL, NULL); +} +#endif + + +static gpgme_error_t +g13_transact (void *engine, + const char *command, + gpgme_assuan_data_cb_t data_cb, + void *data_cb_value, + gpgme_assuan_inquire_cb_t inq_cb, + void *inq_cb_value, + gpgme_assuan_status_cb_t status_cb, + void *status_cb_value) +{ + engine_g13_t g13 = engine; + gpgme_error_t err; + + if (!g13 || !command || !*command) + return gpg_error (GPG_ERR_INV_VALUE); + + g13->user.data_cb = data_cb; + g13->user.data_cb_value = data_cb_value; + g13->user.inq_cb = inq_cb; + g13->user.inq_cb_value = inq_cb_value; + g13->user.status_cb = status_cb; + g13->user.status_cb_value = status_cb_value; + + err = start (g13, command); + return err; +} + + + +static void +g13_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs) +{ + engine_g13_t g13 = engine; + g13->io_cbs = *io_cbs; +} + + +static void +g13_io_event (void *engine, gpgme_event_io_t type, void *type_data) +{ + engine_g13_t g13 = engine; + + TRACE3 (DEBUG_ENGINE, "gpgme:g13_io_event", g13, + "event %p, type %d, type_data %p", + g13->io_cbs.event, type, type_data); + if (g13->io_cbs.event) + (*g13->io_cbs.event) (g13->io_cbs.event_priv, type, type_data); +} + + +struct engine_ops _gpgme_engine_ops_g13 = + { + /* Static functions. */ + _gpgme_get_g13_path, + NULL, + g13_get_version, + g13_get_req_version, + g13_new, + + /* Member functions. */ + g13_release, +#if USE_DESCRIPTOR_PASSING + g13_reset, +#else + NULL, /* reset */ +#endif + NULL, /* set_status_handler */ + NULL, /* set_command_handler */ + NULL, /* set_colon_line_handler */ + g13_set_locale, + NULL, /* set_protocol */ + NULL, /* decrypt */ + NULL, /* decrypt_verify */ + NULL, /* delete */ + NULL, /* edit */ + NULL, /* encrypt */ + NULL, /* encrypt_sign */ + NULL, /* export */ + NULL, /* export_ext */ + NULL, /* genkey */ + NULL, /* import */ + NULL, /* keylist */ + NULL, /* keylist_ext */ + NULL, /* sign */ + NULL, /* trustlist */ + NULL, /* verify */ + NULL, /* getauditlog */ + g13_transact, + NULL, /* conf_load */ + NULL, /* conf_save */ + g13_set_io_cbs, + g13_io_event, + g13_cancel, + g13_cancel_op, + }; diff --git a/src/engine-gpg.c b/src/engine-gpg.c new file mode 100644 index 0000000..cbb456e --- /dev/null +++ b/src/engine-gpg.c @@ -0,0 +1,2393 @@ +/* engine-gpg.c - Gpg Engine. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2009, 2010, 2012 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, see <http://www.gnu.org/licenses/>. +*/ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif + +#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 "priv-io.h" +#include "sema.h" +#include "debug.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. */ + int *arg_locp; /* Write back the argv idx of this argument when + building command line to this location. */ + 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 other side of the pipe */ + int arg_loc; /* The index into the argv for translation purposes. */ + void *tag; +}; + + +typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline); + +struct engine_gpg +{ + char *file_name; + + char *lc_messages; + char *lc_ctype; + + struct arg_and_data_s *arglist; + struct arg_and_data_s **argtail; + + struct + { + int fd[2]; + int arg_loc; + 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]; + int arg_loc; + 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_preprocessor_t preprocess_fnc; + } 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; + + TRACE3 (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg, + "event %p, type %d, type_data %p", + gpg->io_cbs.event, type, type_data); + 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->cmd.fd == fd) + gpg->cmd.fd = -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; + } + } + } +} + +/* If FRONT is true, push at the front of the list. Use this for + options added late in the process. */ +static gpgme_error_t +_add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp) +{ + 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->data = NULL; + a->dup_to = -1; + a->arg_locp = arg_locp; + + strcpy (a->arg, arg); + if (front) + { + a->next = gpg->arglist; + if (!gpg->arglist) + { + /* If this is the first argument, we need to update the tail + pointer. */ + gpg->argtail = &a->next; + } + gpg->arglist = a; + } + else + { + a->next = NULL; + *gpg->argtail = a; + gpg->argtail = &a->next; + } + + return 0; +} + +static gpgme_error_t +add_arg_ext (engine_gpg_t gpg, const char *arg, int front) +{ + return _add_arg (gpg, arg, front, NULL); +} + + +static gpgme_error_t +add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp) +{ + return _add_arg (gpg, arg, 0, locp); +} + + +static gpgme_error_t +add_arg (engine_gpg_t gpg, const char *arg) +{ + return add_arg_ext (gpg, arg, 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; + a->arg_locp = NULL; + + 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 char * +gpg_get_version (const char *file_name) +{ + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_gpg_path ()); +} + + +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 may be waiting for a cmd, close the cmd fd first. On + Windows, close operations block on the reader/writer thread. */ + if (gpg->cmd.used) + { + if (gpg->cmd.fd != -1) + _gpgme_io_close (gpg->cmd.fd); + else if (gpg->fd_data_map + && gpg->fd_data_map[gpg->cmd.idx].fd != -1) + _gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd); + } + + 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; + } + + return 0; +} + +static void +gpg_release (void *engine) +{ + engine_gpg_t gpg = engine; + + if (!gpg) + return; + + gpg_cancel (engine); + + if (gpg->file_name) + free (gpg->file_name); + + if (gpg->lc_messages) + free (gpg->lc_messages); + if (gpg->lc_ctype) + free (gpg->lc_ctype); + + 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 *file_name, const char *home_dir) +{ + engine_gpg_t gpg; + gpgme_error_t rc = 0; + char *dft_display = NULL; + char dft_ttyname[64]; + char *dft_ttytype = NULL; + + gpg = calloc (1, sizeof *gpg); + if (!gpg) + return gpg_error_from_errno (errno); + + if (file_name) + { + gpg->file_name = strdup (file_name); + if (!gpg->file_name) + { + rc = gpg_error_from_errno (errno); + goto leave; + } + } + + gpg->argtail = &gpg->arglist; + gpg->status.fd[0] = -1; + gpg->status.fd[1] = -1; + gpg->colon.fd[0] = -1; + gpg->colon.fd[1] = -1; + gpg->cmd.fd = -1; + gpg->cmd.idx = -1; + gpg->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; + + if (home_dir) + { + rc = add_arg (gpg, "--homedir"); + if (!rc) + rc = add_arg (gpg, home_dir); + if (rc) + goto leave; + } + + rc = add_arg (gpg, "--status-fd"); + if (rc) + goto leave; + + { + char buf[25]; + _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]); + rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc); + 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"); + if (rc) + goto leave; + + rc = _gpgme_getenv ("DISPLAY", &dft_display); + if (rc) + goto leave; + if (dft_display) + { + rc = add_arg (gpg, "--display"); + if (!rc) + rc = add_arg (gpg, dft_display); + + free (dft_display); + } + + if (isatty (1)) + { + int err; + + err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); + if (err) + rc = gpg_error_from_errno (err); + else + { + if (*dft_ttyname) + { + rc = add_arg (gpg, "--ttyname"); + if (!rc) + rc = add_arg (gpg, dft_ttyname); + } + else + rc = 0; + if (!rc) + { + rc = _gpgme_getenv ("TERM", &dft_ttytype); + if (rc) + goto leave; + + if (dft_ttytype) + { + rc = add_arg (gpg, "--ttytype"); + if (!rc) + rc = add_arg (gpg, dft_ttytype); + } + + free (dft_ttytype); + } + } + if (rc) + goto leave; + } + + leave: + if (rc) + gpg_release (gpg); + else + *engine = gpg; + return rc; +} + + +static gpgme_error_t +gpg_set_locale (void *engine, int category, const char *value) +{ + engine_gpg_t gpg = engine; + + if (0) + ; +#ifdef LC_CTYPE + else if (category == LC_CTYPE) + { + if (gpg->lc_ctype) + { + free (gpg->lc_ctype); + gpg->lc_ctype = NULL; + } + if (value) + { + gpg->lc_ctype = strdup (value); + if (!gpg->lc_ctype) + return gpg_error_from_syserror (); + } + } +#endif +#ifdef LC_MESSAGES + else if (category == LC_MESSAGES) + { + if (gpg->lc_messages) + { + free (gpg->lc_messages); + gpg->lc_messages = NULL; + } + if (value) + { + gpg->lc_messages = strdup (value); + if (!gpg->lc_messages) + return gpg_error_from_syserror (); + } + } +#endif /* LC_MESSAGES */ + else + return gpg_error (GPG_ERR_INV_VALUE); + + return 0; +} + + +/* 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) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + engine_gpg_t gpg = (engine_gpg_t) data->handler_value; + gpgme_error_t err; + int processed = 0; + 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, + &processed); + + 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; + + if (err) + return err; + + /* We always need to send at least a newline character. */ + if (!processed) + _gpgme_io_write (fd, "\n", 1); + + return 0; +} + + + +/* The Fnc will be called to get a value for one of the commands with + a key KEY. If the Code passed 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->arg_locp) + *(a->arg_locp) = argc; + + 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) + { + char *ptr; + int buflen = 25; + + argv[argc] = malloc (buflen); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + + ptr = argv[argc]; + if (!a->print_fd) + { + *(ptr++) = '-'; + *(ptr++) = '&'; + buflen -= 2; + } + + _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd); + fd_data_map[datac].arg_loc = argc; + 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; +} + + +/* 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) */ + if (p > buffer && p[-1] == '\r') + p[-1] = 0; + *p = 0; + if (!strncmp (buffer, "[GNUPG:] ", 9) + && buffer[9] >= 'A' && buffer[9] <= 'Z') + { + char *rest; + gpgme_status_code_t r; + + rest = strchr (buffer + 9, ' '); + if (!rest) + rest = p; /* Set to an empty string. */ + else + *rest++ = 0; + + r = _gpgme_parse_status (buffer + 9); + if (r >= 0) + { + if (gpg->cmd.used + && (r == GPGME_STATUS_GET_BOOL + || r == GPGME_STATUS_GET_LINE + || r == GPGME_STATUS_GET_HIDDEN)) + { + gpg->cmd.code = r; + 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) + TRACE0 (DEBUG_CTX, "gpgme:read_status", 0, + "error: unexpected data"); + + 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, rest); + if (err) + return err; + } + + if (r == 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.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) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + engine_gpg_t gpg = (engine_gpg_t) data->handler_value; + 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, ':')) + { + char *line = NULL; + + if (gpg->colon.preprocess_fnc) + { + gpgme_error_t err; + + err = gpg->colon.preprocess_fnc (buffer, &line); + if (err) + return err; + } + + assert (gpg->colon.fnc); + gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer); + if (line) + free (line); + } + + /* 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) +{ + struct io_cb_data *data = (struct io_cb_data *) opaque; + engine_gpg_t gpg = (engine_gpg_t) data->handler_value; + 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_list; + pid_t pid; + + if (!gpg) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!gpg->file_name && !_gpgme_get_gpg_path ()) + return gpg_error (GPG_ERR_INV_ENGINE); + + if (gpg->lc_ctype) + { + rc = add_arg_ext (gpg, gpg->lc_ctype, 1); + if (!rc) + rc = add_arg_ext (gpg, "--lc-ctype", 1); + if (rc) + return rc; + } + + if (gpg->lc_messages) + { + rc = add_arg_ext (gpg, gpg->lc_messages, 1); + if (!rc) + rc = add_arg_ext (gpg, "--lc-messages", 1); + if (rc) + return rc; + } + + rc = build_argv (gpg); + if (rc) + return rc; + + /* status_fd, colon_fd and end of list. */ + n = 3; + for (i = 0; gpg->fd_data_map[i].data; i++) + n++; + fd_list = calloc (n, sizeof *fd_list); + if (! fd_list) + return gpg_error_from_errno (errno); + + /* Build the fd list for the child. */ + n = 0; + fd_list[n].fd = gpg->status.fd[1]; + fd_list[n].dup_to = -1; + fd_list[n].arg_loc = gpg->status.arg_loc; + n++; + if (gpg->colon.fnc) + { + fd_list[n].fd = gpg->colon.fd[1]; + fd_list[n].dup_to = 1; + n++; + } + for (i = 0; gpg->fd_data_map[i].data; i++) + { + fd_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_list[n].dup_to = gpg->fd_data_map[i].dup_to; + fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc; + n++; + } + fd_list[n].fd = -1; + fd_list[n].dup_to = -1; + + status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name : + _gpgme_get_gpg_path (), gpg->argv, + IOSPAWN_FLAG_ALLOW_SET_FG, + fd_list, NULL, NULL, &pid); + saved_errno = errno; + + free (fd_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_event (gpg, 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_arg (gpg, "--"); + if (!err) + err = add_data (gpg, ciph, -1, 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 +gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (!key || !key->subkeys || !key->subkeys->fpr) + return gpg_error (GPG_ERR_INV_CERT_OBJ); + + err = add_arg (gpg, "--passwd"); + if (!err) + 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 +append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */) +{ + gpgme_error_t err = 0; + gpgme_sig_notation_t notation; + + notation = gpgme_sig_notation_get (ctx); + + while (!err && notation) + { + if (notation->name + && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE)) + err = gpg_error (GPG_ERR_INV_VALUE); + else if (notation->name) + { + char *arg; + + /* Maximum space needed is one byte for the "critical" flag, + the name, one byte for '=', the value, and a terminating + '\0'. */ + + arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1); + if (!arg) + err = gpg_error_from_errno (errno); + + if (!err) + { + char *argp = arg; + + if (notation->critical) + *(argp++) = '!'; + + memcpy (argp, notation->name, notation->name_len); + argp += notation->name_len; + + *(argp++) = '='; + + /* We know that notation->name is '\0' terminated. */ + strcpy (argp, notation->value); + } + + if (!err) + err = add_arg (gpg, "--sig-notation"); + if (!err) + err = add_arg (gpg, arg); + + if (arg) + free (arg); + } + else + { + /* This is a policy URL. */ + + char *value; + + if (notation->critical) + { + value = malloc (1 + notation->value_len + 1); + if (!value) + err = gpg_error_from_errno (errno); + else + { + value[0] = '!'; + /* We know that notation->value is '\0' terminated. */ + strcpy (&value[1], notation->value); + } + } + else + value = notation->value; + + if (!err) + err = add_arg (gpg, "--sig-policy-url"); + if (!err) + err = add_arg (gpg, value); + + if (value != notation->value) + free (value); + } + + notation = notation->next; + } + 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 && type == 0) + { + 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 && (flags & GPGME_ENCRYPT_ALWAYS_TRUST)) + err = add_arg (gpg, "--always-trust"); + + if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)) + err = add_arg (gpg, "--no-encrypt-to"); + + 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 (gpgme_data_get_file_name (plain)) + { + if (!err) + err = add_arg (gpg, "--set-filename"); + if (!err) + err = add_arg (gpg, gpgme_data_get_file_name (plain)); + } + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, plain, -1, 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); + if (!err) + err = append_args_from_sig_notations (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 (gpgme_data_get_file_name (plain)) + { + if (!err) + err = add_arg (gpg, "--set-filename"); + if (!err) + err = add_arg (gpg, gpgme_data_get_file_name (plain)); + } + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, plain, -1, 0); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, + gpgme_data_t keydata, int use_armor) +{ + gpgme_error_t err = 0; + + if ((mode & ~(GPGME_EXPORT_MODE_EXTERN + |GPGME_EXPORT_MODE_MINIMAL))) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + + if ((mode & GPGME_EXPORT_MODE_MINIMAL)) + err = add_arg (gpg, "--export-options=export-minimal"); + + if (err) + ; + else if ((mode & GPGME_EXPORT_MODE_EXTERN)) + { + err = add_arg (gpg, "--send-keys"); + } + else + { + 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, "--"); + + return err; +} + + +static gpgme_error_t +gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode, + gpgme_data_t keydata, int use_armor) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = export_common (gpg, mode, keydata, use_armor); + + 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[], gpgme_export_mode_t mode, + gpgme_data_t keydata, int use_armor) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = export_common (gpg, mode, keydata, use_armor); + + 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_arg (gpg, "--"); + if (!err) + err = add_data (gpg, help_data, -1, 0); + + if (!err) + err = start (gpg); + + return err; +} + +/* Return the next DELIM delimited string from DATA as a C-string. + The caller needs to provide the address of a pointer variable which + he has to set to NULL before the first call. After the last call + to this function, this function needs to be called once more with + DATA set to NULL so that the function can release its internal + state. After that the pointer variable is free for use again. + Note that we use a delimiter and thus a trailing delimiter is not + required. DELIM may not be changed after the first call. */ +static const char * +string_from_data (gpgme_data_t data, int delim, + void **helpptr, gpgme_error_t *r_err) +{ +#define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that. */ + struct { + int eof_seen; + int nbytes; /* Length of the last returned string including + the delimiter. */ + int buflen; /* Valid length of BUF. */ + char buf[MYBUFLEN+1]; /* Buffer with one byte extra space. */ + } *self; + char *p; + int nread; + + *r_err = 0; + if (!data) + { + if (*helpptr) + { + free (*helpptr); + *helpptr = NULL; + } + return NULL; + } + + if (*helpptr) + self = *helpptr; + else + { + self = malloc (sizeof *self); + if (!self) + { + *r_err = gpg_error_from_syserror (); + return NULL; + } + *helpptr = self; + self->eof_seen = 0; + self->nbytes = 0; + self->buflen = 0; + } + + if (self->eof_seen) + return NULL; + + assert (self->nbytes <= self->buflen); + memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes); + self->buflen -= self->nbytes; + self->nbytes = 0; + + do + { + /* Fixme: This is fairly infective scanning because we may scan + the buffer several times. */ + p = memchr (self->buf, delim, self->buflen); + if (p) + { + *p = 0; + self->nbytes = p - self->buf + 1; + return self->buf; + } + + if ( !(MYBUFLEN - self->buflen) ) + { + /* Not enough space - URL too long. */ + *r_err = gpg_error (GPG_ERR_TOO_LARGE); + return NULL; + } + + nread = gpgme_data_read (data, self->buf + self->buflen, + MYBUFLEN - self->buflen); + if (nread < 0) + { + *r_err = gpg_error_from_syserror (); + return NULL; + } + self->buflen += nread; + } + while (nread); + + /* EOF reached. If we have anything in the buffer, append a Nul and + return it. */ + self->eof_seen = 1; + if (self->buflen) + { + self->buf[self->buflen] = 0; /* (we allocated one extra byte) */ + return self->buf; + } + return NULL; +#undef MYBUFLEN +} + + + +static gpgme_error_t +gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + int idx; + gpgme_data_encoding_t dataenc; + + if (keydata && keyarray) + return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */ + + dataenc = gpgme_data_get_encoding (keydata); + + if (keyarray) + { + err = add_arg (gpg, "--recv-keys"); + if (!err) + err = add_arg (gpg, "--"); + for (idx=0; !err && keyarray[idx]; idx++) + { + if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP) + ; + else if (!keyarray[idx]->subkeys) + ; + else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr) + err = add_arg (gpg, keyarray[idx]->subkeys->fpr); + else if (*keyarray[idx]->subkeys->keyid) + err = add_arg (gpg, keyarray[idx]->subkeys->keyid); + } + } + else if (dataenc == GPGME_DATA_ENCODING_URL + || dataenc == GPGME_DATA_ENCODING_URL0) + { + void *helpptr; + const char *string; + gpgme_error_t xerr; + int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0; + + /* FIXME: --fetch-keys is probably not correct because it can't + grok all kinds of URLs. On Unix it should just work but on + Windows we will build the command line and that may fail for + some embedded control characters. It is anyway limited to + the maximum size of the command line. We need another + command which can take its input from a file. Maybe we + should use an option to gpg to modify such commands (ala + --multifile). */ + err = add_arg (gpg, "--fetch-keys"); + if (!err) + err = add_arg (gpg, "--"); + helpptr = NULL; + while (!err + && (string = string_from_data (keydata, delim, &helpptr, &xerr))) + err = add_arg (gpg, string); + if (!err) + err = xerr; + string_from_data (NULL, delim, &helpptr, &xerr); + } + else if (dataenc == GPGME_DATA_ENCODING_URLESC) + { + /* Already escaped URLs are not yet supported. */ + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + } + else + { + err = add_arg (gpg, "--import"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, keydata, -1, 0); + } + + if (!err) + err = start (gpg); + + return err; +} + + +/* The output for external keylistings in GnuPG is different from all + the other key listings. We catch this here with a special + preprocessor that reformats the colon handler lines. */ +static gpgme_error_t +gpg_keylist_preprocess (char *line, char **r_line) +{ + enum + { + RT_NONE, RT_INFO, RT_PUB, RT_UID + } + rectype = RT_NONE; +#define NR_FIELDS 16 + char *field[NR_FIELDS]; + int fields = 0; + + *r_line = NULL; + + while (line && fields < NR_FIELDS) + { + field[fields++] = line; + line = strchr (line, ':'); + if (line) + *(line++) = '\0'; + } + + if (!strcmp (field[0], "info")) + rectype = RT_INFO; + else if (!strcmp (field[0], "pub")) + rectype = RT_PUB; + else if (!strcmp (field[0], "uid")) + rectype = RT_UID; + else + rectype = RT_NONE; + + switch (rectype) + { + case RT_INFO: + /* FIXME: Eventually, check the version number at least. */ + return 0; + + case RT_PUB: + if (fields < 7) + return 0; + + /* The format is: + + pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags> + + as defined in 5.2. Machine Readable Indexes of the OpenPGP + HTTP Keyserver Protocol (draft). + + We want: + pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>:::::::: + */ + + if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::", + field[6], field[3], field[2], field[1], + field[4], field[5]) < 0) + return gpg_error_from_errno (errno); + return 0; + + case RT_UID: + /* The format is: + + uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags> + + as defined in 5.2. Machine Readable Indexes of the OpenPGP + HTTP Keyserver Protocol (draft). + + We want: + uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>: + */ + + { + /* The user ID is percent escaped, but we want c-coded. + Because we have to replace each '%HL' by '\xHL', we need at + most 4/3 th the number of bytes. But because we also need + to escape the backslashes we allocate twice as much. */ + char *uid = malloc (2 * strlen (field[1]) + 1); + char *src; + char *dst; + + if (! uid) + return gpg_error_from_errno (errno); + src = field[1]; + dst = uid; + while (*src) + { + if (*src == '%') + { + *(dst++) = '\\'; + *(dst++) = 'x'; + src++; + /* Copy the next two bytes unconditionally. */ + if (*src) + *(dst++) = *(src++); + if (*src) + *(dst++) = *(src++); + } + else if (*src == '\\') + { + *dst++ = '\\'; + *dst++ = '\\'; + } + else + *(dst++) = *(src++); + } + *dst = '\0'; + + if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:", + field[4], field[2], field[3], uid) < 0) + return gpg_error_from_errno (errno); + } + return 0; + + case RT_NONE: + /* Unknown record. */ + break; + } + return 0; + +} + + +static gpg_error_t +gpg_keylist_build_options (engine_gpg_t gpg, int secret_only, + gpgme_keylist_mode_t mode) +{ + gpg_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 + && (mode & GPGME_KEYLIST_MODE_SIGS) + && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)) + { + err = add_arg (gpg, "--list-options"); + if (!err) + err = add_arg (gpg, "show-sig-subpackets=\"20,26\""); + } + if (!err) + { + if ( (mode & GPGME_KEYLIST_MODE_EXTERN) ) + { + if (secret_only) + err = gpg_error (GPG_ERR_NOT_SUPPORTED); + else if ( (mode & GPGME_KEYLIST_MODE_LOCAL)) + { + /* The local+extern mode is special. It works only with + gpg >= 2.0.10. FIXME: We should check that we have + such a version to that we can return a proper error + code. The problem is that we don't know the context + here and thus can't access the cached version number + for the engine info structure. */ + err = add_arg (gpg, "--locate-keys"); + if ((mode & GPGME_KEYLIST_MODE_SIGS)) + err = add_arg (gpg, "--with-sig-check"); + } + else + { + err = add_arg (gpg, "--search-keys"); + gpg->colon.preprocess_fnc = gpg_keylist_preprocess; + } + } + else + { + err = add_arg (gpg, secret_only ? "--list-secret-keys" + : ((mode & GPGME_KEYLIST_MODE_SIGS) + ? "--check-sigs" : "--list-keys")); + } + } + if (!err) + err = add_arg (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 = gpg_keylist_build_options (gpg, secret_only, mode); + + 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 = gpg_keylist_build_options (gpg, secret_only, mode); + + 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); + if (!err) + err = append_args_from_sig_notations (gpg, ctx); + + if (gpgme_data_get_file_name (in)) + { + if (!err) + err = add_arg (gpg, "--set-filename"); + if (!err) + err = add_arg (gpg, gpgme_data_get_file_name (in)); + } + + /* Tell the gpg object about the data. */ + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, in, -1, 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, -1, 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 (!err && signed_text) + err = add_data (gpg, signed_text, -1, 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, + NULL, + gpg_get_version, + gpg_get_req_version, + gpg_new, + + /* Member functions. */ + gpg_release, + NULL, /* reset */ + gpg_set_status_handler, + gpg_set_command_handler, + gpg_set_colon_line_handler, + gpg_set_locale, + NULL, /* set_protocol */ + gpg_decrypt, + gpg_decrypt, /* decrypt_verify */ + 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, + NULL, /* getauditlog */ + NULL, /* opassuan_transact */ + NULL, /* conf_load */ + NULL, /* conf_save */ + gpg_set_io_cbs, + gpg_io_event, + gpg_cancel, + NULL, /* cancel_op */ + gpg_passwd + }; diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c new file mode 100644 index 0000000..6807dce --- /dev/null +++ b/src/engine-gpgconf.c @@ -0,0 +1,928 @@ +/* engine-gpgconf.c - gpg-conf engine. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 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, see <http://www.gnu.org/licenses/>. + */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#include <assert.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <fcntl.h> /* FIXME */ +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "priv-io.h" +#include "sema.h" + +#include "assuan.h" +#include "debug.h" + +#include "engine-backend.h" + + +struct engine_gpgconf +{ + char *file_name; + char *home_dir; +}; + +typedef struct engine_gpgconf *engine_gpgconf_t; + + +static char * +gpgconf_get_version (const char *file_name) +{ + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_gpgconf_path ()); +} + + +static const char * +gpgconf_get_req_version (void) +{ + return NEED_GPGCONF_VERSION; +} + + +static void +gpgconf_release (void *engine) +{ + engine_gpgconf_t gpgconf = engine; + + if (!gpgconf) + return; + + if (gpgconf->file_name) + free (gpgconf->file_name); + if (gpgconf->home_dir) + free (gpgconf->home_dir); + + free (gpgconf); +} + + +static gpgme_error_t +gpgconf_new (void **engine, const char *file_name, const char *home_dir) +{ + gpgme_error_t err = 0; + engine_gpgconf_t gpgconf; + + gpgconf = calloc (1, sizeof *gpgconf); + if (!gpgconf) + return gpg_error_from_errno (errno); + + gpgconf->file_name = strdup (file_name ? file_name + : _gpgme_get_gpgconf_path ()); + if (!gpgconf->file_name) + err = gpg_error_from_syserror (); + + if (!err && home_dir) + { + gpgconf->home_dir = strdup (home_dir); + if (!gpgconf->home_dir) + err = gpg_error_from_syserror (); + } + + if (err) + gpgconf_release (gpgconf); + else + *engine = gpgconf; + + return err; +} + + +static void +release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type) +{ + while (arg) + { + gpgme_conf_arg_t next = arg->next; + + if (alt_type == GPGME_CONF_STRING) + free (arg->value.string); + free (arg); + arg = next; + } +} + + +static void +release_opt (gpgme_conf_opt_t opt) +{ + if (opt->name) + free (opt->name); + if (opt->description) + free (opt->description); + if (opt->argname) + free (opt->argname); + + release_arg (opt->default_value, opt->alt_type); + if (opt->default_description) + free (opt->default_description); + + release_arg (opt->no_arg_value, opt->alt_type); + release_arg (opt->value, opt->alt_type); + release_arg (opt->new_value, opt->alt_type); + + free (opt); +} + + +static void +release_comp (gpgme_conf_comp_t comp) +{ + gpgme_conf_opt_t opt; + + if (comp->name) + free (comp->name); + if (comp->description) + free (comp->description); + if (comp->program_name) + free (comp->program_name); + + opt = comp->options; + while (opt) + { + gpgme_conf_opt_t next = opt->next; + release_opt (opt); + opt = next; + } + + free (comp); +} + + +static void +gpgconf_config_release (gpgme_conf_comp_t conf) +{ + while (conf) + { + gpgme_conf_comp_t next = conf->next; + release_comp (conf); + conf = next; + } +} + + +static gpgme_error_t +gpgconf_read (void *engine, char *arg1, char *arg2, + gpgme_error_t (*cb) (void *hook, char *line), + void *hook) +{ + struct engine_gpgconf *gpgconf = engine; + gpgme_error_t err = 0; +#define LINELENGTH 1024 + char linebuf[LINELENGTH] = ""; + int linelen = 0; + char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL }; + int rp[2]; + struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0}, + {-1, -1} }; + int status; + int nread; + char *mark = NULL; + + argv[1] = arg1; + argv[2] = arg2; + + + /* FIXME: Deal with engine->home_dir. */ + + /* _gpgme_engine_new guarantees that this is not NULL. */ + argv[0] = gpgconf->file_name; + + if (_gpgme_io_pipe (rp, 1) < 0) + return gpg_error_from_syserror (); + + cfd[0].fd = rp[1]; + + status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL); + if (status < 0) + { + _gpgme_io_close (rp[0]); + _gpgme_io_close (rp[1]); + return gpg_error_from_syserror (); + } + + do + { + nread = _gpgme_io_read (rp[0], + linebuf + linelen, LINELENGTH - linelen - 1); + if (nread > 0) + { + char *line; + const char *lastmark = NULL; + size_t nused; + + linelen += nread; + linebuf[linelen] = '\0'; + + for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 ) + { + lastmark = mark; + if (mark > line && mark[-1] == '\r') + mark[-1] = '\0'; + else + mark[0] = '\0'; + + /* Got a full line. Due to the CR removal code (which + occurs only on Windows) we might be one-off and thus + would see empty lines. Don't pass them to the + callback. */ + err = *line? (*cb) (hook, line) : 0; + if (err) + goto leave; + } + + nused = lastmark? (lastmark + 1 - linebuf) : 0; + memmove (linebuf, linebuf + nused, linelen - nused); + linelen -= nused; + } + } + while (nread > 0 && linelen < LINELENGTH - 1); + + if (!err && nread < 0) + err = gpg_error_from_syserror (); + if (!err && nread > 0) + err = gpg_error (GPG_ERR_LINE_TOO_LONG); + + leave: + _gpgme_io_close (rp[0]); + + return err; +} + + +static gpgme_error_t +gpgconf_config_load_cb (void *hook, char *line) +{ + gpgme_conf_comp_t *comp_p = hook; + gpgme_conf_comp_t comp = *comp_p; +#define NR_FIELDS 16 + char *field[NR_FIELDS]; + int fields = 0; + + while (line && fields < NR_FIELDS) + { + field[fields++] = line; + line = strchr (line, ':'); + if (line) + *(line++) = '\0'; + } + + /* We require at least the first 3 fields. */ + if (fields < 2) + return gpg_error (GPG_ERR_INV_ENGINE); + + /* Find the pointer to the new component in the list. */ + while (comp && comp->next) + comp = comp->next; + if (comp) + comp_p = &comp->next; + + comp = calloc (1, sizeof (*comp)); + if (!comp) + return gpg_error_from_syserror (); + /* Prepare return value. */ + comp->_last_opt_p = &comp->options; + *comp_p = comp; + + comp->name = strdup (field[0]); + if (!comp->name) + return gpg_error_from_syserror (); + + comp->description = strdup (field[1]); + if (!comp->description) + return gpg_error_from_syserror (); + + if (fields >= 3) + { + comp->program_name = strdup (field[2]); + if (!comp->program_name) + return gpg_error_from_syserror (); + } + + return 0; +} + + +static gpgme_error_t +gpgconf_parse_option (gpgme_conf_opt_t opt, + gpgme_conf_arg_t *arg_p, char *line) +{ + gpgme_error_t err; + char *mark; + + if (!line[0]) + return 0; + + while (line) + { + gpgme_conf_arg_t arg; + + mark = strchr (line, ','); + if (mark) + *mark = '\0'; + + arg = calloc (1, sizeof (*arg)); + if (!arg) + return gpg_error_from_syserror (); + *arg_p = arg; + arg_p = &arg->next; + + if (*line == '\0') + arg->no_arg = 1; + else + { + switch (opt->alt_type) + { + /* arg->value.count is an alias for arg->value.uint32. */ + case GPGME_CONF_NONE: + case GPGME_CONF_UINT32: + arg->value.uint32 = strtoul (line, NULL, 0); + break; + + case GPGME_CONF_INT32: + arg->value.uint32 = strtol (line, NULL, 0); + break; + + case GPGME_CONF_STRING: + /* The complex types below are only here to silent the + compiler warning. */ + case GPGME_CONF_FILENAME: + case GPGME_CONF_LDAP_SERVER: + case GPGME_CONF_KEY_FPR: + case GPGME_CONF_PUB_KEY: + case GPGME_CONF_SEC_KEY: + case GPGME_CONF_ALIAS_LIST: + /* Skip quote character. */ + line++; + + err = _gpgme_decode_percent_string (line, &arg->value.string, + 0, 0); + if (err) + return err; + break; + } + } + + /* Find beginning of next value. */ + if (mark++ && *mark) + line = mark; + else + line = NULL; + } + + return 0; +} + + +static gpgme_error_t +gpgconf_config_load_cb2 (void *hook, char *line) +{ + gpgme_error_t err; + gpgme_conf_comp_t comp = hook; + gpgme_conf_opt_t *opt_p = comp->_last_opt_p; + gpgme_conf_opt_t opt; +#define NR_FIELDS 16 + char *field[NR_FIELDS]; + int fields = 0; + + while (line && fields < NR_FIELDS) + { + field[fields++] = line; + line = strchr (line, ':'); + if (line) + *(line++) = '\0'; + } + + /* We require at least the first 10 fields. */ + if (fields < 10) + return gpg_error (GPG_ERR_INV_ENGINE); + + opt = calloc (1, sizeof (*opt)); + if (!opt) + return gpg_error_from_syserror (); + + comp->_last_opt_p = &opt->next; + *opt_p = opt; + + if (field[0][0]) + { + opt->name = strdup (field[0]); + if (!opt->name) + return gpg_error_from_syserror (); + } + + opt->flags = strtoul (field[1], NULL, 0); + + opt->level = strtoul (field[2], NULL, 0); + + if (field[3][0]) + { + opt->description = strdup (field[3]); + if (!opt->description) + return gpg_error_from_syserror (); + } + + opt->type = strtoul (field[4], NULL, 0); + + opt->alt_type = strtoul (field[5], NULL, 0); + + if (field[6][0]) + { + opt->argname = strdup (field[6]); + if (!opt->argname) + return gpg_error_from_syserror (); + } + + if (opt->flags & GPGME_CONF_DEFAULT) + { + err = gpgconf_parse_option (opt, &opt->default_value, field[7]); + if (err) + return err; + } + else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0]) + { + opt->default_description = strdup (field[7]); + if (!opt->default_description) + return gpg_error_from_syserror (); + } + + if (opt->flags & GPGME_CONF_NO_ARG_DESC) + { + opt->no_arg_description = strdup (field[8]); + if (!opt->no_arg_description) + return gpg_error_from_syserror (); + } + else + { + err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]); + if (err) + return err; + } + + err = gpgconf_parse_option (opt, &opt->value, field[9]); + if (err) + return err; + + return 0; +} + + +static gpgme_error_t +gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p) +{ + gpgme_error_t err; + gpgme_conf_comp_t comp = NULL; + gpgme_conf_comp_t cur_comp; + + *comp_p = NULL; + + err = gpgconf_read (engine, "--list-components", NULL, + gpgconf_config_load_cb, &comp); + if (err) + { + gpgconf_release (comp); + return err; + } + + cur_comp = comp; + while (!err && cur_comp) + { + err = gpgconf_read (engine, "--list-options", cur_comp->name, + gpgconf_config_load_cb2, cur_comp); + cur_comp = cur_comp->next; + } + + if (err) + { + gpgconf_release (comp); + return err; + } + + *comp_p = comp; + return 0; +} + + + +gpgme_error_t +_gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p, + gpgme_conf_type_t type, const void *value) +{ + gpgme_conf_arg_t arg; + + arg = calloc (1, sizeof (*arg)); + if (!arg) + return gpg_error_from_syserror (); + + if (!value) + arg->no_arg = 1; + else + { + /* We need to switch on type here because the alt-type is not + yet known. */ + switch (type) + { + case GPGME_CONF_NONE: + case GPGME_CONF_UINT32: + arg->value.uint32 = *((unsigned int *) value); + break; + + case GPGME_CONF_INT32: + arg->value.int32 = *((int *) value); + break; + + case GPGME_CONF_STRING: + case GPGME_CONF_FILENAME: + case GPGME_CONF_LDAP_SERVER: + case GPGME_CONF_KEY_FPR: + case GPGME_CONF_PUB_KEY: + case GPGME_CONF_SEC_KEY: + case GPGME_CONF_ALIAS_LIST: + arg->value.string = strdup (value); + if (!arg->value.string) + { + free (arg); + return gpg_error_from_syserror (); + } + break; + + default: + free (arg); + return gpg_error (GPG_ERR_INV_VALUE); + } + } + + *arg_p = arg; + return 0; +} + + +void +_gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type) +{ + /* Lacking the alt_type we need to switch on type here. */ + switch (type) + { + case GPGME_CONF_NONE: + case GPGME_CONF_UINT32: + case GPGME_CONF_INT32: + case GPGME_CONF_STRING: + default: + break; + + case GPGME_CONF_FILENAME: + case GPGME_CONF_LDAP_SERVER: + case GPGME_CONF_KEY_FPR: + case GPGME_CONF_PUB_KEY: + case GPGME_CONF_SEC_KEY: + case GPGME_CONF_ALIAS_LIST: + type = GPGME_CONF_STRING; + break; + } + + release_arg (arg, type); +} + + +gpgme_error_t +_gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg) +{ + if (reset) + { + if (opt->new_value) + release_arg (opt->new_value, opt->alt_type); + opt->new_value = NULL; + opt->change_value = 0; + } + else + { + /* Support self-assignment, for example for adding an item to an + existing list. */ + if (opt->new_value && arg != opt->new_value) + release_arg (opt->new_value, opt->alt_type); + opt->new_value = arg; + opt->change_value = 1; + } + return 0; +} + + +/* FIXME: Major problem: We don't get errors from gpgconf. */ + +static gpgme_error_t +gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf) +{ + struct engine_gpgconf *gpgconf = engine; + gpgme_error_t err = 0; +#define BUFLEN 1024 + char buf[BUFLEN]; + int buflen = 0; + char *argv[] = { NULL /* file_name */, arg1, arg2, 0 }; + int rp[2]; + struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} }; + int status; + int nwrite; + + /* FIXME: Deal with engine->home_dir. */ + + /* _gpgme_engine_new guarantees that this is not NULL. */ + argv[0] = gpgconf->file_name; + + if (_gpgme_io_pipe (rp, 0) < 0) + return gpg_error_from_syserror (); + + cfd[0].fd = rp[0]; + + status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL); + if (status < 0) + { + _gpgme_io_close (rp[0]); + _gpgme_io_close (rp[1]); + return gpg_error_from_syserror (); + } + + for (;;) + { + if (buflen == 0) + { + do + { + buflen = gpgme_data_read (conf, buf, BUFLEN); + } + while (buflen < 0 && errno == EAGAIN); + + if (buflen < 0) + { + err = gpg_error_from_syserror (); + _gpgme_io_close (rp[1]); + return err; + } + else if (buflen == 0) + { + /* All is written. */ + _gpgme_io_close (rp[1]); + return 0; + } + } + + do + { + nwrite = _gpgme_io_write (rp[1], buf, buflen); + } + while (nwrite < 0 && errno == EAGAIN); + + if (nwrite > 0) + { + buflen -= nwrite; + if (buflen > 0) + memmove (&buf[0], &buf[nwrite], buflen); + } + else if (nwrite < 0) + { + _gpgme_io_close (rp[1]); + return gpg_error_from_syserror (); + } + } + + return 0; +} + + +static gpgme_error_t +arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg) +{ + gpgme_error_t err = 0; + int amt = 0; + char buf[16]; + + while (amt >= 0 && arg) + { + switch (option->alt_type) + { + case GPGME_CONF_NONE: + case GPGME_CONF_UINT32: + default: + snprintf (buf, sizeof (buf), "%u", arg->value.uint32); + buf[sizeof (buf) - 1] = '\0'; + amt = gpgme_data_write (conf, buf, strlen (buf)); + break; + + case GPGME_CONF_INT32: + snprintf (buf, sizeof (buf), "%i", arg->value.uint32); + buf[sizeof (buf) - 1] = '\0'; + amt = gpgme_data_write (conf, buf, strlen (buf)); + break; + + + case GPGME_CONF_STRING: + /* The complex types below are only here to silent the + compiler warning. */ + case GPGME_CONF_FILENAME: + case GPGME_CONF_LDAP_SERVER: + case GPGME_CONF_KEY_FPR: + case GPGME_CONF_PUB_KEY: + case GPGME_CONF_SEC_KEY: + case GPGME_CONF_ALIAS_LIST: + /* One quote character, and three times to allow + for percent escaping. */ + { + char *ptr = arg->value.string; + amt = gpgme_data_write (conf, "\"", 1); + if (amt < 0) + break; + + while (!err && *ptr) + { + switch (*ptr) + { + case '%': + amt = gpgme_data_write (conf, "%25", 3); |