diff options
Diffstat (limited to 'libkdenetwork/libgpgme-copy')
98 files changed, 33099 insertions, 0 deletions
diff --git a/libkdenetwork/libgpgme-copy/Makefile.am b/libkdenetwork/libgpgme-copy/Makefile.am new file mode 100644 index 000000000..34527396a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = assuan gpgme diff --git a/libkdenetwork/libgpgme-copy/assuan/ChangeLog b/libkdenetwork/libgpgme-copy/assuan/ChangeLog new file mode 100644 index 000000000..a3b3f9281 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/ChangeLog @@ -0,0 +1,829 @@ +2006-11-22 Werner Koch <wk@g10code.com> + + * assuan-handler.c (fun1_cookie_write, fun2_cookie_write): New. + (assuan_get_data_fp) [HAVE_FUNOPEN]: Use it. + +2006-11-21 Werner Koch <wk@g10code.com> + + * Makefile.am (libassuan_pth_a_CFLAGS): New. + + * assuan-pipe-server.c (_assuan_release_context): Free CMDTBL. + +2006-11-14 Werner Koch <wk@g10code.com> + + * libassuan.m4 (AM_CHECK_LIBASSUAN): New. + + * assuan-handler.c (assuan_register_post_cmd_notify) + (assuan_register_post_cmd_notify): New. + * assuan-util.c (assuan_set_io_monitor): New. + * assuan-buffer.c (_assuan_read_line): Use it. + (_assuan_write_line): Ditto. + (_assuan_cookie_write_data): Ditto. + (_assuan_cookie_write_flush): Ditto. + +2006-10-18 Werner Koch <wk@g10code.com> + + * libassuan.m4: Pass "pthread" to the common macro. Reported by + Rex Dieter. + +2006-10-16 Werner Koch <wk@g10code.com> + + * mkerrors: Map ASSUAN_Not_Confirmed. + +2006-10-10 Werner Koch <wk@g10code.com> + + * libassuan.m4 (AM_PATH_LIBASSUAN_PTH) + (AM_PATH_LIBASSUAN_PTHREAD): Fixed. + + * assuan-buffer.c (assuan_sendfd): Implement a runtime detection + of implemented descripotr passing. + + * assuan-uds.c: Take care of USE_DESCRIPTOR_PASSING. + + * assuan-defs.h: Add missing semicolon. + +2006-10-09 Werner Koch <wk@g10code.com> + + * assuan-handler.c (process_request): Use weak pragma for the sake + of old gcc's. Reported by Alain Guibert. + + * assuan-io.c: Removed Pth support. + * assuan-io-pth.c: New. Based on assuan-io.c + +2006-10-06 Werner Koch <wk@g10code.com> + + * libassuan-config.in: New options --api-version and --thread. + +2006-10-04 Werner Koch <wk@g10code.com> + + * assuan-client.c (assuan_transact): Need to map old assuan status + codes so that for example CANCELED is correctly mapped. + +2006-09-28 Marcus Brinkmann <marcus@g10code.de> + + * assuan-client.c (assuan_transact): Do not convert error on + status line, it is already a gpg-error. Do convert + ASSUAN_Server_Fault. + +2006-09-19 Marcus Brinkmann <marcus@g10code.de> + + * assuan.h (assuan_init_socket_server_ext) + [_ASSUAN_EXT_SYM_PREFIX]: Fix typo in macro. + +2006-09-19 Werner Koch <wk@g10code.com> + + * assuan-defs.h (putc_unlocked): Add prototype. + + * assuan-socket-server.c (accept_connection): Made LEN a socklen_t. + + * assuan.h: Replaced assuan error code enum by simple defines and + made assuan_error_t an int. + * mkerrors: Changed parser accordingly. + +2006-09-19 Marcus Brinkmann <marcus@g10code.de> + + * assuan-pipe-connect.c: Add hacks for Slowaris. + * assuan-socket.c: Likewise here. + + * assuan.h (enum): Avoid trailing comma in enumerator list. Ugh. + + * mkerrors (_assuan_error): Change return type to assuan_error_t. + * assuan-buffer.c (_assuan_read_line): Change return type to + assuan_error_t. Map returned value of -1. + (_assuan_write_line): Change type of RC to assuan_error_t. + * assuan-defs.h (_assuan_read_line, _assuan_error): Likewise for + prototypes. + + * assuan-defs.h (unsetenv): Define correctly. + +2006-09-14 Werner Koch <wk@g10code.com> + + * assuan-io.c (_assuan_waitpid): New. Changed all waitpid calls + to this. + + * assuan.h (_ASSUAN_DEPRECATED): New internal macro. + (assuan_pipe_connect2): Declare deprecated. + (assuan_init_connected_socket_server): Declare deprecated. + + * assuan-connect.c (assuan_get_peercred): New. + * assuan-socket-server.c (accept_connection_bottom): Save uid and gid. + +2006-09-13 Werner Koch <wk@g10code.com> + + * assuan-client.c (assuan_transact): Need to map the error code. + * mkerrors: Need to map ASSUAN_No_Secret_Key. + + * assuan-pipe-server.c (is_valid_socket): New. + (assuan_init_pipe_server): Use UDS with the environmet variable is + set and a valid descriptor is given. Ignore FILEDES in this case. + + * assuan-socket-server.c (assuan_init_socket_server_ext): New. + Changed other init fucntions to make use of it. + + * assuan-handler.c (assuan_command_parse_fd): Allow for lowercase + "fd". + (std_handler_reset): Close pending fds. + * assuan-uds.c (uds_receivefd): Fixed. + (_assuan_uds_close_fds): New. + + * assuan-socket-connect.c (assuan_socket_connect_ext): New. Takes + all code of assuan_socket_connect plus an option to use sendmsg. + * assuan-pipe-connect.c (assuan_pipe_connect_ext): New arg FLAGS. + +2006-09-12 Werner Koch <wk@g10code.com> + + * assuan-buffer.c (_assuan_write_line): Also log the prefix. + + * assuan-defs.h (DIM, DIMof): New. + + * assuan-domain-server.c: Removed. + * assuan-domain-connect.c: Renamed to .. + * assuan-uds.c: this. + (domain_reader, domain_writer, domain_sendfd, domain_receivefd) + (assuan_domain_connect, _assuan_domain_init): Removed. + (uds_reader, uds_writer, uds_sendfd, uds_receivefd) + (_assuan_init_uds_io): New. + (_assuan_uds_deinit): New. + + * assuan-io.c (_assuan_simple_sendmsg, _assuan_simple_recvmsg): New. + (my_pth_fdmode, my_pth_select): New. + +2006-09-11 Werner Koch <wk@g10code.com> + + * assuan-pipe-server.c (assuan_init_pipe_server): Allow for + FILEDES to be NULL and try to start as a socketpair server in this + case. + + * assuan-pipe-connect.c (assuan_pipe_connect2): Split up into two + functions (unix and w32) for clarity. + (pipe_connect_unix): This is the new fucntion. Add USE_CMSG flag. + (pipe_connect_w32): Ditto. + (initial_handshake): Factored out code. + (socketpair_connect): New. + (assuan_pipe_connect_ext): New. + (do_finish): Handle case if outbound and inbound fd are the same. + This is to support socketpairs. + +2006-09-10 Werner Koch <wk@g10code.com> + + * assuan-util.c (_assuan_log_print_buffer) + (_assuan_log_sanitized_string,assuan_set_log_stream): Moved to .. + * assuan-logging.c: .. here. + (_assuan_log_print_buffer): Only print the leading bytes in hex + log mode unless the new env variable ASSUAN_FULL_LOGGING has been + set. + (_assuan_set_default_log_stream): Test this env variable. + +2006-09-06 Werner Koch <wk@g10code.com> + + * assuan.h (_ASSUAN_ONLY_GPG_ERRORS): New. + + * assuan-handler.c (dispatch_command): Use Syntax_Error instead of + Invalid_Command. + + * assuan-domain-connect.c: Changed alloc malloc/free/realloc to + xtrymalloc et al. + (read_int, write_int): Make args void pointers. + (domain_receivefd): Take care of realloc shrinking failure. + + * assuan-buffer.c (_assuan_read_line, _assuan_write_line) + (assuan_write_line, _assuan_cookie_write_data) + (_assuan_cookie_write_flush): Print the inbound fd instead of the + address of the context when logging I/0. This makes it more + readable. + +2006-09-05 Werner Koch <wk@g10code.com> + + * assuan-defs.h (err_code, err_is_eof): New. + + * mkerrors (_assuan_error): New. Wrapped all error code + assignments in a call to this. + (assuan_strerror): Map gpg-style error codes back. Also print a + string for the old EOF code. + (assuan_set_assuan_err_source): New. + + * assuan-logging.c (_assuan_log_printf): Do not change ERRNO and + print the pid. + + * assuan-domain-connect.c (domain_reader): Replaced plain printf + by assuan_log function. + +2005-10-24 Werner Koch <wk@g10code.com> + + * putc_unlocked.c, memrchr.c, isascii.c, funopen.c: Changed + distribution terms to LGPL. This are small and trivial files so + there are no obstacles of doing so. + * assuan-socket.c: Likewise, the stated GPL was not intended. + +2005-10-08 Marcus Brinkmann <marcus@g10code.de> + + * assuan-defs.h (setenv, unsetenv, clearenv) [!HAVE_SETENV]: + Define to _assuan_*. + * setenv.c: Include "assuan-defs.h". + (__add_to_environ): Make static. + +2005-10-07 Marcus Brinkmann <marcus@g10code.de> + + * assuan-defs.h (memrchr) [!HAVE_MEMRCHR]: New prototype. + (stpcpy) [!HAVE_STPCPY]: Likewise. + * stpcpy.c: New LGPL'ed file from the GNU C Library. + * setenv.c: New file. + * assuan-domain-connect.c (read_int): New function. + (write_int): New function. + (domain_reader): Use read_int. + (domain_sendfd): Use write_int. + +2005-10-01 Marcus Brinkmann <marcus@g10code.de> + + * assuan.h (assuan_pipe_connect, assuan_pipe_connect2): Make type + of ARGV parameter const in prototype. + * assuan-pipe-connect.c (assuan_pipe_connect, + assuan_pipe_connect2): Likewise in declaration. + (assuan_pipe_connect2): Add braindead cast to make execv happy. + + * assuan-client.c (assuan_transact): Change LINE, S and D from + unsigned char * to char * to silence gcc warning. + * assuan-util.c (_assuan_log_sanitized_string): Add explicit cast + to silence gcc warning. + * assuan-inquire.c (assuan_inquire): Likewise. + +2005-08-19 Werner Koch <wk@g10code.com> + + * funopen.c, assuan-socket.c: Copied from libassuan CVS. + * assuan-pipe-connect.c (assuan_pipe_connect2): Add missing + declaration of PID. + +2005-08-09 Werner Koch <wk@g10code.com> + + * README.1st: Adjusted to cope with changes done in upstream Assuan. + + Merged changes for W32 support from libassuan. + + * assuan.h [_ASSUAN_EXT_SYM_PREFIX]: New. + * assuan-io.c [_ASSUAN_NO_PTH]: New. + * assuan-pipe-connect.c (fix_signals) [_ASSUAN_NO_FIXED_SIGNALS]: New. + (assuan_pipe_connect2) [_ASSUAN_USE_DOUBLE_FORK]: Use double fork. + (fix_signals) [_ASSUAN_USE_DOUBLE_FORK]: Do not wait.. + * assuan-logging.c, assuan-io.c: Include config.h + Replaced all usages of _WIN32 by the new HAVE_W32_SYSTEM because + there is nothing winning in this API. + * assuan-pipe-connect.c (assuan_pipe_connect2) [_WIN32]: Return + error Not Imlemented. + * assuan-logging.c (_assuan_w32_strerror): New. + * assuan-defs.h (w32_strerror): new. + * assuan-pipe-connect.c (assuan_pipe_connect2, fix_signals): + Factored signal code out to new function. + (build_w32_commandline, create_inheritable_pipe): New. Taken + from gnupg 1.9. + (assuan_pipe_connect2) [W32]: Implemented for W32. + * assuan-pipe-server.c (assuan_init_pipe_server) [W32]: Map file + descriptors using _get_osfhandle. + * assuan-socket-connect.c (assuan_socket_connect) [W32]: Allow for + a drive letter in the path. + * assuan-client.c (assuan_transact): Handle empty and comment + commands correctly. + * assuan-util.c (_assuan_calloc): Avoid integer overflow. + * assuan-util.c (assuan_set_flag, assuan_get_flag): New. + * assuan-defs.h (struct assuan_context_s): New field flags. + * assuan.h (assuan_flag_t): New with one flag value + ASSUAN_NO_WAITPID for now. + * assuan-pipe-connect.c (do_finish): Take care of the no_waitpid + flag. + * mkerrors: Include config.h into assuan-errors.c. This is + required so that assuan.h knows about the W32 macro. + +2005-08-09 Timo Schulz <twoaday@g10code.com> (ported from libassuan by wk) + + * assuan-io.c (_assuan_simple_read, _assuan_simple_write): W32 + support. + * assuan-socket.c (_assuan_close): New. + (_assuan_sock_new): New. + (_assuan_sock_bind): New. + +2005-03-22 Werner Koch <wk@g10code.com> + + * assuan-defs.h (struct assuan_io): Renamed elements READ and + WRITE to READFNC and WRITEFNC to avoid problems with read defined + as macro. Changed callers. Noted by Ville Skyttä. + +2004-12-16 Marcus Brinkmann <marcus@g10code.de> + + * assuan-pipe-connect.c (do_finish): Do not wait for child to finish. + (assuan_pipe_connect): Use double-fork approach. + * assuan-connect.c (assuan_disconnect): Do not write BYE to the + status line. + +2004-12-07 Marcus Brinkmann <marcus@g10code.de> + + * README.1st: Add copyright notice. + +2004-06-23 Marcus Brinkmann <marcus@g10code.de> + + * assuan-domain-connect.c [HAVE_SYS_UIO_H]: Include <sys/uio.h>. + + * assuan-handler.c: Include <errno.h>. + +2004-06-08 Marcus Brinkmann <marcus@g10code.de> + + * assuan-buffer.c (assuan_write_line): If the line is longer than + the maximum line length, bail out early. + +2004-04-19 Werner Koch <wk@gnupg.org> + + * assuan-socket-connect.c: Include sys/types.h + * assuan-socket-server.c: Ditto + * assuan-domain-connect.c: Ditto. + +2004-02-18 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (assuan_get_data_fp): Fail with ENOSYS if we + can't implement this. + +2004-02-13 Werner Koch <wk@gnupg.org> + + * assuan-domain-connect.c: Removed the unneeded alloca.h + +2003-08-13 Werner Koch <wk@gnupg.org> + + * assuan-inquire.c (assuan_inquire): Increase length of cmdbuf to + the Assuan limit. + +2003-06-24 Werner Koch <wk@gnupg.org> + + * mkerrors: Kludge to print libgpg-error values in an easier + readable way. + +2003-04-29 Werner Koch <wk@gnupg.org> + + * libassuan.m4: New. Based on libgrypt.m4. + * Makefile.am (m4data_DATA): New. + + * assuan.h (AssuanCommand): Removed. + + * assuan-handler.c: Remove the cmd_id element, + (assuan_register_command): Likewise. Note that semantics changed. + (_assuan_register_std_commands): Adjusted. + +2003-02-22 Neal H. Walfield <neal@g10code.de> + + * Makefile.am (bin_SCRIPTS): Renamed from bin_PROGRAMS. + +2003-02-18 Neal H. Walfield <neal@g10code.de> + + * Makefile.am (libassuan_a_LIBADD): New variable. + * funopen.c: Move from ../common. + * isascii.c: Likewise. + * memrchr.c: Likewise. + * putc_unlocked.c: Likewise. + +2003-02-18 Neal H. Walfield <neal@g10code.de> + + * assuan-handler.c (_IO_cookie_io_functions_t): Remove. + (cookie_io_functions_t): Remove. + (fopencookie): Remove prototype. + (assuan_get_data_fp): Use funopen, not fopencookie. + +2003-02-18 Neal H. Walfield <neal@g10code.de> + + * libassuan-config.in: New file. + * Makefile.am (bin_PROGRAMS): New variable. + +2003-02-17 Neal H. Walfield <neal@g10code.de> + + * .cvsignore: New file. + +2003-02-17 Neal H. Walfield <neal@g10code.de> + + * Makefile.am (lib_LIBRARIES): Use this instead of . . . + (noinst_LIBRARIES): . . . this. + (include_HEADERS): New variable. + (libassuan_a_SOURCES): Remove assuan.h, add assuan-logging.c. + + * assuan.h (assuan_set_assuan_log_stream): New prototype. + (assuan_get_assuan_log_stream): Likewise. + (assuan_get_assuan_log_prefix): Likewise. + * assuan-logging.c: New file. + + * assuan-buffer.c [HAVE_JNLIB_LOGGIN]: Do not include + "../jnlib/logging.h". + (my_log_prefix): Remove function. + (_assuan_read_line): Use assuan_get_assuan_log_prefix in lieu of + my_log_prefix. + (assuan_write_line): Likewise. + (_assuan_cookie_write_data): Likewise. + (_assuan_cookie_write_flush): Likewise. + * assuan-domain-connect.c (LOGERROR, LOGERROR1, LOGERROR2, + LOGERRORX): Remove. + (LOG): New macro. + (domain_reader): Use it. + (domain_writer): Likewise. + (domain_sendfd): Likewise. + (domain_receivefd): Likewise. + (_assuan_domain_init): Likewise. + (assuan_domain_connect): Likewise. + * assuan-pipe-connect.c [HAVE_JNLIB_LOGGIN]: Do not include + "../jnlib/logging.h". + (LOGERROR, LOGERROR1, LOGERROR2, LOGERRORX): Remove. + (LOG): New macro. + (assuan_pipe_connect): Use it. + * assuan-socket-connect.c [HAVE_JNLIB_LOGGIN]: Do not include + "../jnlib/logging.h". + (LOGERROR, LOGERROR1, LOGERROR2, LOGERRORX): Remove. + (LOG): New macro. + (assuan_socket_connect): Use it. + (socket_reader): Remove dead code. + (socket_writer): Likewise. + * assuan-util.c [HAVE_JNLIB_LOGGIN]: Do not include + "../jnlib/logging.h". + (_assuan_log_sanitized_string): Use assuan_get_assuan_log_stream, + not jnlib. + +2002-11-24 Neal H. Walfield <neal@g10code.de> + + * assuan.h (assuan_command_parse_fd): New prototype. + * assuan-handler.c (assuan_command_parse_fd): Rename from + parse_cmd_input_output. Export. + (std_handler_input): Update to use assuan_command_parse_fd. + (std_handler_output): Likewise. + +2002-11-24 Neal H. Walfield <neal@g10code.de> + + * assuan.h (assuan_sendfd): New prototype. + (assuan_receivefd): New prototype. + * assuan-buffer.c (assuan_sendfd): New function. + (assuan_receivefd): New function. + * assuan-handler.c (parse_cmd_input_output): Recognize incoming + file descriptors and act appropriately. + * assuan-defs.h (struct assuan_io): Add fields sendfd and + receivefd. + (struct assuan_context_s): Add fields pendingfds and + pendingfdscount. + * assuan-pipe-server.c (_assuan_new_context): Update IO to reflect + new features. + * assuan-domain-connect.c (do_deinit): Cleanup any unreceived file + descriptors. + (domain_reader): Receive file descriptors. + (domain_sendfd): New function. + (domain_receivefd): New function. + (_assuan_domain_init): Update initialization code to reflect new + features. + +2002-11-24 Neal H. Walfield <neal@g10code.de> + + * assuan-domain-connect.c (do_finish): Remove. + (_assuan_domain_init): Use default handlers where possible. + Add an assert and update comments. + * assuan-domain-server.c (accept_connection): Remove. + (assuan_init_domain_server): Use default handlers where possible. + Put the server in pipe mode: it can only be used by a single + client. + +2002-11-24 Neal H. Walfield <neal@g10code.de> + + * assuan.h: Add prototype for assuan_domain_connect and + assuan_init_domain_server. + * assuan-defs.h: Include <unistd.h>. + Add prototype for _assuan_domain_init. + * assuan-domain-connect.c: New file. + * assuan-domain-server.c: New file. + * Makefile.am (libassuan_a_SOURCES): Add assuan-domain-connect.c + and assuan-domain-server.c + +2002-11-23 Neal H. Walfield <neal@g10code.de> + + * Makefile.am (libassuan_a_SOURCES): Add assuan-io.c. + * assuan-io.c: Restore. + (_assuan_simple_read): Rename from _assuan_read. + (_assuan_simple_write): Rename from _assuan_write. + * assuan-defs.h (_assuan_simple_read): New prototype. + (_assuan_simple_write): Likewise. + * assuan-pipe-server.c (pipe_reader): Remove. + (pipe_writer): Remove. + (_assuan_new_context): Initialize IO is with _assuan_simple_read + and _assuan_simple_write. + * assuan-socket-connect.c (socket_reader): Remove. + (socket_writer): Remove. + (assuan_socket_connect): Initialize IO is with _assuan_simple_read + and _assuan_simple_write. + * assuan-socket-server.c (io): New local variable. + (assuan_init_socket_server): Initialize CTX->io. + (assuan_init_connected_socket_server): Likewise. + +2002-11-23 Neal H. Walfield <neal@g10code.de> + + * assuan-buffer.c (readline): Use memrchr. + (_assuan_read_line): Rewritten to use the string functions. + +2002-11-20 Neal H. Walfield <neal@g10code.de> + + * assuan-socket-connect.c (assuan_socket_connect): Pass PF_LOCAL + to socket(), not AF_UNIX: it expects a PF_* macro and the former + is more portable. + (assuan_socket_connect): Use AF_LOCAL, not AF_UNIX which is more + POSIXy. + +2002-11-20 Neal H. Walfield <neal@g10code.de> + + * assuan-defs.h (struct assuan_io): New structure. + (struct assuan_context_s): New field, io. + (_assuan_read): Depreciated. + (_assuan_write): Likewise. + * assuan-pipe-server.c: Include <unistd.h>. + (pipe_reader): New function. + (pipe_writer): Likewise. + (_assuan_new_context.IO): New local static. Set to pipe_reader + and pipe_writer. Use it to initialize new context. + * assuan-socket-connect.c (socket_reader): New function. + (socket_writer): New function. + (assuan_socket_connect.IO): New local static. Set to socket_reader + and socket_writer. Use it to initialize new context. + * assuan-buffer.c (writen): Take an ASSUAN_CONTEXT rather than a + file descriptor. Do not use _assuan_write but the write method + in the supplied context. + (readline): Likewise for _assuan_read. + (assuan_write_line): When calling writen, pass CTX; not the file + descriptor directly. + (_assuan_cookie_write_data): Likewise. + (_assuan_cookie_write_flush): Likewise. + (_assuan_read_line): Likewise for readline. + * Makefile.am (libassuan_a_SOURCES): Remove assuan-io.c. + * assuan-io.c: Removed. + +2002-11-10 Werner Koch <wk@gnupg.org> + + * assuan-pipe-connect.c (assuan_pipe_connect): Changed the order + of the dups to handle cases where we have already used fd 2 for + other things. + +2002-10-31 Neal H. Walfield <neal@g10code.de> + + * assuan-util.c: Include <ctype.h>. + (_assuan_log_print_buffer): Elide the magic numbers preferring the + standard isfoo functions. Use putc_unlocked where possible. + (_assuan_log_sanitized_string): Rewrite to use putc_unlocked and + the isfoo functions. + +2002-09-05 Neal H. Walfield <neal@g10code.de> + + * assuan-defs.h (_assuan_read_wrapper): Depreciated. + * assuan-util.c (_assuan_read_wrapper): Removed. + * assuan-defs.h (_assuan_write_wrapper): Depreciated. + * assuan-util.c (_assuan_write_wrapper): Removed. + * assuan.h (assuan_set_io_fun): Depreciated. + * assuan-util.c (assuan_set_io_fun): Removed. + + * assuan-defs.h (_assuan_read): New function. + (_assuan_write): Likewise. + * assuan-io.c: New file. + + * assuan-buffer.c (writen): Use _assuan_write rather than doing + the work here. + (readline): Likewise for _assuan_read. + + * Makefile.am (libassuan_a_SOURCES): Add assuan-io.c. + +2002-08-16 Werner Koch <wk@gnupg.org> + + * assuan.h: Renamed Bad_Certificate_Path to Bad_Certificate_Chain. + +2002-07-30 Werner Koch <wk@gnupg.org> + + Changed the license from GPL to LGPL. + +2002-07-23 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (_IO_cookie_io_functions_t): Define it here if + it does not exists. + +2002-06-27 Werner Koch <wk@gnupg.org> + + * assuan-pipe-connect.c (assuan_pipe_connect): No special handling + for the log_fd and stderr. Connect stderr to /dev/null if it + should not be retained. + +2002-06-26 Werner Koch <wk@gnupg.org> + + * assuan-buffer.c (assuan_write_line): Make sure we never + accidently print an extra LF. + +2002-05-23 Werner Koch <wk@gnupg.org> + + * assuan-util.c (assuan_set_io_func): New. + * assuan-buffer.c (writen, readline): Use the new functions + instead of pth. + * assuan-socket-server.c (accept_connection): Don't use the + pth_accept - using the assuan included accept code would be a bad + idea within Pth so we don't need a replacement function. + +2002-05-22 Werner Koch <wk@gnupg.org> + + * assuan-socket-server.c (assuan_init_connected_socket_server): New. + (accept_connection): Factored most code out to.. + (accept_connection_bottom): .. new function. + +2002-04-04 Werner Koch <wk@gnupg.org> + + * assuan-buffer.c (my_log_prefix): New. Use it for all i/o debug + output. + +2002-03-06 Werner Koch <wk@gnupg.org> + + * assuan-client.c (_assuan_read_from_server): Detect END. + (assuan_transact): Pass it to the data callback. + +2002-02-27 Werner Koch <wk@gnupg.org> + + * assuan-client.c (assuan_transact): Add 2 more arguments to + support status lines. Passing NULL yields the old behaviour. + + * assuan-handler.c (process_request): Flush data lines send + without using the data fp. + +2002-02-14 Werner Koch <wk@gnupg.org> + + * assuan-inquire.c (assuan_inquire): Check for a cancel command + and return ASSUAN_Canceled. Allow for non-data inquiry. + + * assuan.h: Add a few token specific error codes. + +2002-02-13 Werner Koch <wk@gnupg.org> + + * assuan-defs.h (assuan_context_s): New var CLIENT_PID. + * assuan-pipe-server.c (_assuan_new_context): set default value. + * assuan-socket-server.c (accept_connection): get the actual pid. + +2002-02-12 Werner Koch <wk@gnupg.org> + + * assuan-buffer.c (writen,readline) [USE_GNU_PT]: Use pth_read/write. + * assuan-socket-server.c (accept_connection) [USE_GNU_PTH]: Ditto. + +2002-02-01 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (MOSTLYCLEANFILES): New variable. + +2002-01-23 Werner Koch <wk@gnupg.org> + + * assuan-socket-connect.c (LOGERRORX): and removed typo. + +2002-01-22 Marcus Brinkmann <marcus@g10code.de> + + * assuan-socket-connect.c (LOGERRORX): Reverse arguments to fputs. + +2002-01-21 Werner Koch <wk@gnupg.org> + + * assuan-connect.c: Move all except assuan_get_pid to... + * assuan-pipe-connect.c: this. + (assuan_pipe_disconnect): Removed. + (do_finish, do_deinit): New + (assuan_pipe_connect): and set them into the context. + * assuan-socket-connect.c: New. + + * assuan-util.c (_assuan_log_sanitized_string): New. + + * assuan-pipe-server.c (assuan_init_pipe_server): Factored most + code out to ... + (_assuan_new_context): new func. + (_assuan_release_context): New + * assuan-connect.c (assuan_pipe_connect): Use the new functions. + +2002-01-20 Werner Koch <wk@gnupg.org> + + * assuan.h: Added Invalid Option error code. + + * assuan-handler.c (std_handler_option): New. + (std_cmd_tbl): Add OPTION as standard command. + (assuan_register_option_handler): New. + (dispatch_command): Use case insensitive matching as a fallback. + (my_strcasecmp): New. + +2002-01-19 Werner Koch <wk@gnupg.org> + + * assuan-buffer.c (_assuan_read_line): Add output logging. + (assuan_write_line): Ditto. + (_assuan_cookie_write_data): Ditto. + (_assuan_cookie_write_flush): Ditto. + * assuan-util.c (_assuan_log_print_buffer): New. + (assuan_set_log_stream): New. + (assuan_begin_confidential): New. + (assuan_end_confidential): New. + + * assuan-defs.h: Add a few handler variables. + * assuan-pipe-server.c (assuan_deinit_pipe_server): Removed. + (deinit_pipe_server): New. + (assuan_deinit_server): New. Changed all callers to use this. + * assuan-listen.c (assuan_accept): Use the accept handler. + * assuan-handler.c (process_request): Use the close Handler. + * assuan-socket-server.c: New. + +2002-01-14 Werner Koch <wk@gnupg.org> + + * assuan-client.c (_assuan_read_from_server): Skip spaces after + the keyword. + +2002-01-03 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (assuan_set_okay_line): New. + (process_request): And use it here. + +2002-01-02 Werner Koch <wk@gnupg.org> + + * assuan-inquire.c (init_membuf,put_membuf,get_membuf): Apply a + hidden 0 behind the buffer so that the buffer can be used as a + string in certain contexts. + +2001-12-14 Marcus Brinkmann <marcus@g10code.de> + + * assuan-connect.c (assuan_pipe_connect): New argument + FD_CHILD_LIST. Don't close those fds. + * assuan.h: Likewise for prototype. + +2001-12-14 Werner Koch <wk@gnupg.org> + + * assuan-listen.c (assuan_close_input_fd): New. + (assuan_close_output_fd): New. + * assuan-handler.c (std_handler_reset): Always close them after a + reset command. + (std_handler_bye): Likewise. + +2001-12-14 Marcus Brinkmann <marcus@g10code.de> + + * assuan-buffer.c (_assuan_read_line): New variable ATTICLEN, use + it to save the length of the attic line. + Rediddle the code a bit to make it more clear what happens. + +2001-12-14 Marcus Brinkmann <marcus@g10code.de> + + * assuan-defs.h (LINELENGTH): Define as ASSUAN_LINELENGTH. + assuan.h: Define ASSUAN_LINELENGTH. + +2001-12-13 Marcus Brinkmann <marcus@g10code.de> + + * assuan-buffer.c (assuan_read_line): Fix order of execution to + get correct return values. + +2001-12-13 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (assuan_get_active_fds): Fixed silly bug, + pretty obvious that nobody ever tested this function. + +2001-12-12 Werner Koch <wk@gnupg.org> + + * assuan-connect.c (assuan_pipe_connect): Implemented the inital + handshake. + * assuan-client.c (read_from_server): Renamed to + (_assuan_read_from_server): this and made external. + + * assuan-listen.c (assuan_set_hello_line): New. + (assuan_accept): Use a custom hello line is available. + + * assuan-buffer.c (assuan_read_line): New. + (assuan_pending_line): New. + (_assuan_write_line): Renamed to .. + (assuan_write_line): this, made public and changed all callers. + +2001-12-04 Werner Koch <wk@gnupg.org> + + * assuan-connect.c (assuan_pipe_connect): Add more error reporting. + * assuan-client.c: New. + + * assuan-inquire.c: New. + * assuan-handler.c (process_request): Check for nested invocations. + +2001-11-27 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (assuan_register_input_notify): New. + (assuan_register_output_notify): New. + +2001-11-26 Werner Koch <wk@gnupg.org> + + * assuan.h: Added more status codes. + +2001-11-25 Werner Koch <wk@gnupg.org> + + * assuan-handler.c (assuan_register_bye_notify) + (assuan_register_reset_notify) + (assuan_register_cancel_notify): New and call them from the + standard handlers. + (assuan_process): Moved bulk of function to .. + (process_request): .. new. + (assuan_process_next): One shot version of above. + (assuan_get_active_fds): New. + +2001-11-24 Werner Koch <wk@gnupg.org> + + * assuan-connect.c (assuan_get_pid): New. + + * assuan-buffer.c (_assuan_read_line): Deal with reads of more + than a line. + * assuan-defs.h: Add space in the context for this. + + + Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/libkdenetwork/libgpgme-copy/assuan/Makefile.am b/libkdenetwork/libgpgme-copy/assuan/Makefile.am new file mode 100644 index 000000000..aea8f558c --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/Makefile.am @@ -0,0 +1,58 @@ +# Assuan Makefile +# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +# +# This file is part of Assuan. +# +# Assuan 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. +# +# Assuan 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 + +## Process this file with automake to produce Makefile.in + +#EXTRA_DIST = mkerrors +INCLUDES = -I.. # -I$(top_srcdir)/include +#BUILT_SOURCES = assuan-errors.c +#MOSTLYCLEANFILES = assuan-errors.c + +noinst_LTLIBRARIES = libassuan.la + +AM_CPPFLAGS = -D_ASSUAN_IN_GPGME_BUILD_ASSUAN + +#libassuan_la_LDFLAGS = +libassuan_la_SOURCES = \ + assuan-util.c \ + assuan-errors.c \ + assuan-buffer.c \ + assuan-handler.c \ + assuan-inquire.c \ + assuan-listen.c \ + assuan-connect.c \ + assuan-client.c \ + assuan-pipe-server.c \ + assuan-socket-server.c \ + assuan-pipe-connect.c \ + assuan-socket-connect.c \ + assuan-socket.c \ + assuan-io.c \ + assuan-uds.c \ + funopen.c \ + assuan-logging.c + +libassuan_la_COMPILE_FIRST=assuan-errors.c + +assuan-errors.c : $(srcdir)/assuan.h + $(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c + +CLEANFILES=assuan-errors.c + + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-buffer.c b/libkdenetwork/libgpgme-copy/assuan/assuan-buffer.c new file mode 100644 index 000000000..b06025b46 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-buffer.c @@ -0,0 +1,550 @@ +/* assuan-buffer.c - read and send data + * Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> +#ifdef HAVE_W32_SYSTEM +#include <process.h> +#endif +#include "assuan-defs.h" + + +/* Extended version of write(2) to guarantee that all bytes are + written. Returns 0 on success or -1 and ERRNO on failure. */ +static int +writen (assuan_context_t ctx, const char *buffer, size_t length) +{ + while (length) + { + ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length); + + if (nwritten < 0) + { + if (errno == EINTR) + continue; + return -1; /* write error */ + } + length -= nwritten; + buffer += nwritten; + } + return 0; /* okay */ +} + +/* Read an entire line. Returns 0 on success or -1 and ERRNo on + failure. EOF is indictated by setting the integer at address + R_EOF. */ +static int +readline (assuan_context_t ctx, char *buf, size_t buflen, + int *r_nread, int *r_eof) +{ + size_t nleft = buflen; + char *p; + + *r_eof = 0; + *r_nread = 0; + while (nleft > 0) + { + ssize_t n = ctx->io->readfnc (ctx, buf, nleft); + + if (n < 0) + { + if (errno == EINTR) + continue; + return -1; /* read error */ + } + else if (!n) + { + *r_eof = 1; + break; /* allow incomplete lines */ + } + p = buf; + nleft -= n; + buf += n; + *r_nread += n; + + p = memrchr (p, '\n', n); + if (p) + break; /* at least one full line available - that's enough for now */ + } + + return 0; +} + + +/* Function returns an Assuan error. */ +assuan_error_t +_assuan_read_line (assuan_context_t ctx) +{ + char *line = ctx->inbound.line; + int nread, atticlen; + int rc; + char *endp = 0; + + if (ctx->inbound.eof) + return _assuan_error (-1); + + atticlen = ctx->inbound.attic.linelen; + if (atticlen) + { + memcpy (line, ctx->inbound.attic.line, atticlen); + ctx->inbound.attic.linelen = 0; + + endp = memchr (line, '\n', atticlen); + if (endp) + /* Found another line in the attic. */ + { + rc = 0; + nread = atticlen; + atticlen = 0; + } + else + /* There is pending data but not a full line. */ + { + assert (atticlen < LINELENGTH); + rc = readline (ctx, line + atticlen, + LINELENGTH - atticlen, &nread, &ctx->inbound.eof); + } + } + else + /* No pending data. */ + rc = readline (ctx, line, LINELENGTH, + &nread, &ctx->inbound.eof); + if (rc) + { + if (ctx->log_fp) + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd, + strerror (errno)); + return _assuan_error (ASSUAN_Read_Error); + } + if (!nread) + { + assert (ctx->inbound.eof); + if (ctx->log_fp) + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + return _assuan_error (-1); + } + + ctx->inbound.attic.pending = 0; + nread += atticlen; + + if (! endp) + endp = memchr (line, '\n', nread); + + if (endp) + { + unsigned monitor_result; + int n = endp - line + 1; + + if (n < nread) + /* LINE contains more than one line. We copy it to the attic + now as handlers are allowed to modify the passed + buffer. */ + { + int len = nread - n; + memcpy (ctx->inbound.attic.line, endp + 1, len); + ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0; + ctx->inbound.attic.linelen = len; + } + + if (endp != line && endp[-1] == '\r') + endp --; + *endp = 0; + + ctx->inbound.linelen = endp - line; + + monitor_result = (ctx->io_monitor + ? ctx->io_monitor (ctx, 0, + ctx->inbound.line, + ctx->inbound.linelen) + : 0); + if ( (monitor_result & 2) ) + ctx->inbound.linelen = 0; + + if (ctx->log_fp && !(monitor_result & 1)) + { + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->inbound.line, + ctx->inbound.linelen); + putc ('\n', ctx->log_fp); + } + return 0; + } + else + { + if (ctx->log_fp) + fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + *line = 0; + ctx->inbound.linelen = 0; + return _assuan_error (ctx->inbound.eof + ? ASSUAN_Line_Not_Terminated + : ASSUAN_Line_Too_Long); + } +} + + +/* Read the next line from the client or server and return a pointer + in *LINE to a buffer holding the line. LINELEN is the length of + *LINE. The buffer is valid until the next read operation on it. + The caller may modify the buffer. The buffer is invalid (i.e. must + not be used) if an error is returned. + + Returns 0 on success or an assuan error code. + See also: assuan_pending_line(). +*/ +assuan_error_t +assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen) +{ + assuan_error_t err; + + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + + err = _assuan_read_line (ctx); + *line = ctx->inbound.line; + *linelen = ctx->inbound.linelen; + return err; +} + + +/* Return true if a full line is buffered (i.e. an entire line may be + read without any I/O). */ +int +assuan_pending_line (assuan_context_t ctx) +{ + return ctx && ctx->inbound.attic.pending; +} + + +assuan_error_t +_assuan_write_line (assuan_context_t ctx, const char *prefix, + const char *line, size_t len) +{ + assuan_error_t rc = 0; + size_t prefixlen = prefix? strlen (prefix):0; + unsigned int monitor_result; + + /* Make sure that the line is short enough. */ + if (len + prefixlen + 2 > ASSUAN_LINELENGTH) + { + if (ctx->log_fp) + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " + "[supplied line too long -truncated]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + if (prefixlen > 5) + prefixlen = 5; + if (len > ASSUAN_LINELENGTH - prefixlen - 2) + len = ASSUAN_LINELENGTH - prefixlen - 2 - 1; + } + + monitor_result = (ctx->io_monitor + ? ctx->io_monitor (ctx, 1, line, len) + : 0); + + /* Fixme: we should do some kind of line buffering. */ + if (ctx->log_fp && !(monitor_result & 1)) + { + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + { + if (prefixlen) + _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen); + _assuan_log_print_buffer (ctx->log_fp, line, len); + } + putc ('\n', ctx->log_fp); + } + + if (prefixlen && !(monitor_result & 2)) + { + rc = writen (ctx, prefix, prefixlen); + if (rc) + rc = _assuan_error (ASSUAN_Write_Error); + } + if (!rc && !(monitor_result & 2)) + { + rc = writen (ctx, line, len); + if (rc) + rc = _assuan_error (ASSUAN_Write_Error); + if (!rc) + { + rc = writen (ctx, "\n", 1); + if (rc) + rc = _assuan_error (ASSUAN_Write_Error); + } + } + return rc; +} + + +assuan_error_t +assuan_write_line (assuan_context_t ctx, const char *line) +{ + size_t len; + const char *s; + + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + + /* Make sure that we never take a LF from the user - this might + violate the protocol. */ + s = strchr (line, '\n'); + len = s? (s-line) : strlen (line); + + if (ctx->log_fp && s) + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> " + "[supplied line contained a LF - truncated]\n", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + + return _assuan_write_line (ctx, NULL, line, len); +} + + + +/* Write out the data in buffer as datalines with line wrapping and + percent escaping. This function is used for GNU's custom streams. */ +int +_assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size) +{ + assuan_context_t ctx = cookie; + size_t size = orig_size; + char *line; + size_t linelen; + + if (ctx->outbound.data.error) + return 0; + + line = ctx->outbound.data.line; + linelen = ctx->outbound.data.linelen; + line += linelen; + while (size) + { + unsigned int monitor_result; + + /* Insert data line header. */ + if (!linelen) + { + *line++ = 'D'; + *line++ = ' '; + linelen += 2; + } + + /* Copy data, keep space for the CRLF and to escape one character. */ + while (size && linelen < LINELENGTH-2-2) + { + if (*buffer == '%' || *buffer == '\r' || *buffer == '\n') + { + sprintf (line, "%%%02X", *(unsigned char*)buffer); + line += 3; + linelen += 3; + buffer++; + } + else + { + *line++ = *buffer++; + linelen++; + } + size--; + } + + + monitor_result = (ctx->io_monitor + ? ctx->io_monitor (ctx, 1, + ctx->outbound.data.line, linelen) + : 0); + + if (linelen >= LINELENGTH-2-2) + { + if (ctx->log_fp && !(monitor_result & 1)) + { + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->outbound.data.line, + linelen); + putc ('\n', ctx->log_fp); + } + *line++ = '\n'; + linelen++; + if ( !(monitor_result & 2) + && writen (ctx, ctx->outbound.data.line, linelen)) + { + ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error); + return 0; + } + line = ctx->outbound.data.line; + linelen = 0; + } + } + + ctx->outbound.data.linelen = linelen; + return (int)orig_size; +} + + +/* Write out any buffered data + This function is used for GNU's custom streams */ +int +_assuan_cookie_write_flush (void *cookie) +{ + assuan_context_t ctx = cookie; + char *line; + size_t linelen; + unsigned int monitor_result; + + if (ctx->outbound.data.error) + return 0; + + line = ctx->outbound.data.line; + linelen = ctx->outbound.data.linelen; + line += linelen; + + monitor_result = (ctx->io_monitor + ? ctx->io_monitor (ctx, 1, + ctx->outbound.data.line, linelen) + : 0); + + if (linelen) + { + if (ctx->log_fp && !(monitor_result & 1)) + { + fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ", + assuan_get_assuan_log_prefix (), + (unsigned int)getpid (), ctx->inbound.fd); + if (ctx->confidential) + fputs ("[Confidential data not shown]", ctx->log_fp); + else + _assuan_log_print_buffer (ctx->log_fp, + ctx->outbound.data.line, linelen); + putc ('\n', ctx->log_fp); + } + *line++ = '\n'; + linelen++; + if ( !(monitor_result & 2) + && writen (ctx, ctx->outbound.data.line, linelen)) + { + ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error); + return 0; + } + ctx->outbound.data.linelen = 0; + } + return 0; +} + + +/** + * assuan_send_data: + * @ctx: An assuan context + * @buffer: Data to send or NULL to flush + * @length: length of the data to send/ + * + * This function may be used by the server or the client to send data + * lines. The data will be escaped as required by the Assuan protocol + * and may get buffered until a line is full. To force sending the + * data out @buffer may be passed as NULL (in which case @length must + * also be 0); however when used by a client this flush operation does + * also send the terminating "END" command to terminate the reponse on + * a INQUIRE response. However, when assuan_transact() is used, this + * function takes care of sending END itself. + * + * Return value: 0 on success or an error code + **/ + +assuan_error_t +assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + if (!buffer && length) + return _assuan_error (ASSUAN_Invalid_Value); + + if (!buffer) + { /* flush what we have */ + _assuan_cookie_write_flush (ctx); + if (ctx->outbound.data.error) + return ctx->outbound.data.error; + if (!ctx->is_server) + return assuan_write_line (ctx, "END"); + } + else + { + _assuan_cookie_write_data (ctx, buffer, length); + if (ctx->outbound.data.error) + return ctx->outbound.data.error; + } + + return 0; +} + +assuan_error_t +assuan_sendfd (assuan_context_t ctx, int fd) +{ + /* It is explicitly allowed to use (NULL, -1) as a runtime test to + check whether descriptor passing is available. */ + if (!ctx && fd == -1) +#ifdef USE_DESCRIPTOR_PASSING + return 0; +#else + return _assuan_error (ASSUAN_Not_Implemented); +#endif + + if (! ctx->io->sendfd) + return set_error (ctx, Not_Implemented, + "server does not support sending and receiving " + "of file descriptors"); + return ctx->io->sendfd (ctx, fd); +} + +assuan_error_t +assuan_receivefd (assuan_context_t ctx, int *fd) +{ + if (! ctx->io->receivefd) + return set_error (ctx, Not_Implemented, + "server does not support sending and receiving " + "of file descriptors"); + return ctx->io->receivefd (ctx, fd); +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-client.c b/libkdenetwork/libgpgme-copy/assuan/assuan-client.c new file mode 100644 index 000000000..978c69546 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-client.c @@ -0,0 +1,234 @@ +/* assuan-client.c - client functions + * Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <assert.h> + +#include "assuan-defs.h" + +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) + + +assuan_error_t +_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) +{ + char *line; + int linelen; + assuan_error_t rc; + + *okay = 0; + *off = 0; + do + { + rc = _assuan_read_line (ctx); + if (rc) + return rc; + line = ctx->inbound.line; + linelen = ctx->inbound.linelen; + } + while (*line == '#' || !linelen); + + if (linelen >= 1 + && line[0] == 'D' && line[1] == ' ') + { + *okay = 2; /* data line */ + *off = 2; + } + else if (linelen >= 1 + && line[0] == 'S' + && (line[1] == '\0' || line[1] == ' ')) + { + *okay = 4; + *off = 1; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + *okay = 1; + *off = 2; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + *okay = 0; + *off = 3; + while (line[*off] == ' ') + ++*off; + } + 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] == ' ')) + { + *okay = 3; + *off = 7; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (line[3] == '\0' || line[3] == ' ')) + { + *okay = 5; /* end line */ + *off = 3; + } + else + rc = _assuan_error (ASSUAN_Invalid_Response); + return rc; +} + + + +/** + * assuan_transact: + * @ctx: The Assuan context + * @command: Command line to be send to the server + * @data_cb: Callback function for data lines + * @data_cb_arg: first argument passed to @data_cb + * @inquire_cb: Callback function for a inquire response + * @inquire_cb_arg: first argument passed to @inquire_cb + * @status_cb: Callback function for a status response + * @status_cb_arg: first argument passed to @status_cb + * + * FIXME: Write documentation + * + * Return value: 0 on success or error code. The error code may be + * the one one returned by the server in error lines or from the + * callback functions. Take care: When a callback returns an error + * this function returns immediately with an error and thus the caller + * will altter return an Assuan error (write erro in most cases). + **/ +assuan_error_t +assuan_transact (assuan_context_t ctx, + const char *command, + int (*data_cb)(void *, const void *, size_t), + void *data_cb_arg, + int (*inquire_cb)(void*, const char *), + void *inquire_cb_arg, + int (*status_cb)(void*, const char *), + void *status_cb_arg) +{ + assuan_error_t rc; + int okay, off; + char *line; + int linelen; + + rc = assuan_write_line (ctx, command); + if (rc) + return rc; + + if (*command == '#' || !*command) + return 0; /* Don't expect a response for a comment line. */ + + again: + rc = _assuan_read_from_server (ctx, &okay, &off); + if (rc) + return rc; /* error reading from server */ + + line = ctx->inbound.line + off; + linelen = ctx->inbound.linelen - off; + + if (!okay) + { + rc = atoi (line); + if (rc > 0 && rc < 100) + rc = _assuan_error (ASSUAN_Server_Fault); + else if (rc > 0 && rc <= 128) + rc = _assuan_error (rc); + } + else if (okay == 2) + { + if (!data_cb) + rc = _assuan_error (ASSUAN_No_Data_Callback); + else + { + char *s, *d; + + for (s=d=line; linelen; linelen--) + { + if (*s == '%' && linelen > 2) + { /* handle escaping */ + s++; + *d++ = xtoi_2 (s); + s += 2; + linelen -= 2; + } + else + *d++ = *s++; + } + *d = 0; /* add a hidden string terminator */ + rc = data_cb (data_cb_arg, line, d - line); + if (!rc) + goto again; + } + } + else if (okay == 3) + { + if (!inquire_cb) + { + assuan_write_line (ctx, "END"); /* get out of inquire mode */ + _assuan_read_from_server (ctx, &okay, &off); /* dummy read */ + rc = _assuan_error (ASSUAN_No_Inquire_Callback); + } + else + { + rc = inquire_cb (inquire_cb_arg, line); + if (!rc) + rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */ + if (!rc) + goto again; + } + } + else if (okay == 4) + { + if (status_cb) + rc = status_cb (status_cb_arg, line); + if (!rc) + goto again; + } + else if (okay == 5) + { + if (!data_cb) + rc = _assuan_error (ASSUAN_No_Data_Callback); + else + { + rc = data_cb (data_cb_arg, NULL, 0); + if (!rc) + goto again; + } + } + + return rc; +} + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-connect.c b/libkdenetwork/libgpgme-copy/assuan/assuan-connect.c new file mode 100644 index 000000000..92995d8c1 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-connect.c @@ -0,0 +1,79 @@ +/* assuan-connect.c - Establish a connection (client) + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/wait.h> +#endif + +#include "assuan-defs.h" + +/* Disconnect and release the context CTX. */ +void +assuan_disconnect (assuan_context_t ctx) +{ + if (ctx) + { + assuan_write_line (ctx, "BYE"); + ctx->finish_handler (ctx); + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + _assuan_release_context (ctx); + } +} + +/* Return the PID of the peer or -1 if not known. This function works + in some situations where assuan_get_ucred fails. */ +pid_t +assuan_get_pid (assuan_context_t ctx) +{ + return (ctx && ctx->pid)? ctx->pid : -1; +} + + +/* Return user credentials. PID, UID and GID amy be gived as NULL if + you are not interested in this value. For getting the pid of the + peer the assuan_get_pid is usually better suited. */ +assuan_error_t +assuan_get_peercred (assuan_context_t ctx, pid_t *pid, uid_t *uid, gid_t *gid) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + if (!ctx->peercred.valid) + return _assuan_error (ASSUAN_General_Error); + if (pid) + *pid = ctx->peercred.pid; + if (uid) + *uid = ctx->peercred.uid; + if (gid) + *gid = ctx->peercred.gid; + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-defs.h b/libkdenetwork/libgpgme-copy/assuan/assuan-defs.h new file mode 100644 index 000000000..fa04f0b29 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-defs.h @@ -0,0 +1,323 @@ +/* assuan-defs.c - Internal definitions to Assuan + * Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifndef ASSUAN_DEFS_H +#define ASSUAN_DEFS_H + +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/socket.h> +#include <sys/un.h> +#else +#include <windows.h> +#endif +#include <unistd.h> + +#include "assuan.h" + +#ifndef HAVE_W32_SYSTEM +#define DIRSEP_C '/' +#else +#define DIRSEP_C '\\' +#endif + +#ifdef HAVE_W32_SYSTEM +#define AF_LOCAL AF_UNIX +/* We need to prefix the structure with a sockaddr_in header so we can + use it later for sendto and recvfrom. */ +struct sockaddr_un +{ + short sun_family; + unsigned short sun_port; + struct in_addr sun_addr; + char sun_path[108-2-4]; /* Path name. */ +}; + +/* Not needed anymore because the current mingw32 defines this in + sys/types.h */ +/* typedef int ssize_t; */ + +/* Missing W32 functions */ +int putc_unlocked (int c, FILE *stream); +void * memrchr (const void *block, int c, size_t size); +char * stpcpy (char *dest, const char *src); +#endif + +#define LINELENGTH ASSUAN_LINELENGTH + + +struct cmdtbl_s +{ + const char *name; + int (*handler)(assuan_context_t, char *line); +}; + + +/* A structure to dispatch I/O functions. All these functions need to + return 0 on success and set ERRNO on failure. */ +struct assuan_io +{ + /* Routine to read from input_fd. */ + ssize_t (*readfnc) (assuan_context_t, void *, size_t); + /* Routine to write to output_fd. */ + ssize_t (*writefnc) (assuan_context_t, const void *, size_t); + /* Send a file descriptor. */ + assuan_error_t (*sendfd) (assuan_context_t, int); + /* Receive a file descriptor. */ + assuan_error_t (*receivefd) (assuan_context_t, int *); +}; + + +/* The context we use with most functions. */ +struct assuan_context_s +{ + assuan_error_t err_no; + const char *err_str; + int os_errno; /* Last system error number used with certain + error codes. */ + + /* Context specific flags (cf. assuan_flag_t). */ + struct + { + unsigned int no_waitpid:1; /* See ASSUAN_NO_WAITPID. */ + } flags; + + int confidential; + int is_server; /* Set if this is context belongs to a server */ + int in_inquire; + char *hello_line; + char *okay_line; /* See assuan_set_okay_line() */ + + void *user_pointer; /* For assuan_get_pointer and assuan_set_pointer (). */ + + FILE *log_fp; + + struct { + int fd; + int eof; + char line[LINELENGTH]; + int linelen; /* w/o CR, LF - might not be the same as + strlen(line) due to embedded nuls. However a nul + is always written at this pos. */ + struct { + char line[LINELENGTH]; + int linelen ; + int pending; /* i.e. at least one line is available in the attic */ + } attic; + } inbound; + + struct { + int fd; + struct { + FILE *fp; + char line[LINELENGTH]; + int linelen; + int error; + } data; + } outbound; + + int pipe_mode; /* We are in pipe mode, i.e. we can handle just one + connection and must terminate then. */ + pid_t pid; /* The pid of the peer. */ + int listen_fd; /* The fd we are listening on (used by socket servers) */ + int connected_fd; /* helper */ + + struct { + int valid; /* Whether this structure has valid information. */ + pid_t pid; /* The pid of the peer. */ + uid_t uid; /* The uid of the peer. */ + gid_t gid; /* The gid of the peer. */ + } peercred; + + /* Used for Unix domain sockets. */ + struct sockaddr_un myaddr; + struct sockaddr_un serveraddr; + + /* Structure used for unix domain socket buffering. FIXME: We don't + use datagrams anymore thus we could get away with a simpler + buffering approach. */ + struct { + void *buffer; /* Malloced buffer. */ + int bufferallocated; /* Memory allocated. */ + int bufferoffset; /* Offset of start of buffer. */ + int buffersize; /* Bytes buffered. */ + + int pendingfds[5]; /* Array to save received descriptors. */ + int pendingfdscount; /* Number of received descriptors. */ + } uds; + + void (*deinit_handler)(assuan_context_t); + int (*accept_handler)(assuan_context_t); + int (*finish_handler)(assuan_context_t); + + struct cmdtbl_s *cmdtbl; + size_t cmdtbl_used; /* used entries */ + size_t cmdtbl_size; /* allocated size of table */ + + void (*bye_notify_fnc)(assuan_context_t); + void (*reset_notify_fnc)(assuan_context_t); + void (*cancel_notify_fnc)(assuan_context_t); + int (*option_handler_fnc)(assuan_context_t,const char*, const char*); + void (*input_notify_fnc)(assuan_context_t, const char *); + void (*output_notify_fnc)(assuan_context_t, const char *); + + /* This function is called right after a command has been processed. + It may be used to command related cleanup. */ + void (*post_cmd_notify_fnc)(assuan_context_t, int); + + /* If set, this is called right before logging an I/O line. With + DIRECTION set to 1 it is called for an output oeration; 0 means + an input operation. If bit 0 is set in the return value, the + logging of the will be suppressed. With bit 1 set, the entire + line will be ignored. */ + unsigned int (*io_monitor)(assuan_context_t ctx, + int direction, + const char *line, + size_t linelen); + + int input_fd; /* set by INPUT command */ + int output_fd; /* set by OUTPUT command */ + + /* io routines. */ + struct assuan_io *io; +}; + +/*-- assuan-pipe-server.c --*/ +int _assuan_new_context (assuan_context_t *r_ctx); +void _assuan_release_context (assuan_context_t ctx); + +/*-- assuan-uds.c --*/ +void _assuan_uds_close_fds (assuan_context_t ctx); +void _assuan_uds_deinit (assuan_context_t ctx); +void _assuan_init_uds_io (assuan_context_t ctx); + + +/*-- assuan-handler.c --*/ +int _assuan_register_std_commands (assuan_context_t ctx); + +/*-- assuan-buffer.c --*/ +assuan_error_t _assuan_read_line (assuan_context_t ctx); +int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size); +int _assuan_cookie_write_flush (void *cookie); +assuan_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, + const char *line, size_t len); + +/*-- assuan-client.c --*/ +assuan_error_t _assuan_read_from_server (assuan_context_t ctx, + int *okay, int *off); + +/*-- assuan-error.c --*/ + + +/* Map error codes as used in this implementaion to the libgpg-error + codes. */ +assuan_error_t _assuan_error (int oldcode); + +/* Extrac the erro code from A. This works for both the old and the + new style error codes. This needs to be whenever an error code is + compared. */ +#define err_code(a) ((a) & 0x00ffffff) + +/* Check whether A is the erro code for EOF. We allow forold and new + style EOF error codes here. */ +#define err_is_eof(a) ((a) == (-1) || err_code (a) == 16383) + + + +/*-- assuan-util.c --*/ +void *_assuan_malloc (size_t n); +void *_assuan_calloc (size_t n, size_t m); +void *_assuan_realloc (void *p, size_t n); +void _assuan_free (void *p); + +#define xtrymalloc(a) _assuan_malloc ((a)) +#define xtrycalloc(a,b) _assuan_calloc ((a),(b)) +#define xtryrealloc(a,b) _assuan_realloc((a),(b)) +#define xfree(a) _assuan_free ((a)) + +#define set_error(c,e,t) \ + assuan_set_error ((c), _assuan_error (ASSUAN_ ## e), (t)) + +#ifdef HAVE_W32_SYSTEM +const char *_assuan_w32_strerror (int ec); +#define w32_strerror(e) _assuan_w32_strerror ((e)) +#endif /*HAVE_W32_SYSTEM*/ + + +/*-- assuan-logging.c --*/ +void _assuan_set_default_log_stream (FILE *fp); + +void _assuan_log_printf (const char *format, ...) +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) + __attribute__ ((format (printf,1,2))) +#endif + ; +void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length); +void _assuan_log_sanitized_string (const char *string); + + +/*-- assuan-io.c --*/ +pid_t _assuan_waitpid (pid_t pid, int *status, int options); + +ssize_t _assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size); +ssize_t _assuan_simple_write (assuan_context_t ctx, const void *buffer, + size_t size); +ssize_t _assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg); +ssize_t _assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg); + +/*-- assuan-socket.c --*/ +int _assuan_close (int fd); +int _assuan_sock_new (int domain, int type, int proto); +int _assuan_sock_bind (int sockfd, struct sockaddr *addr, int addrlen); +int _assuan_sock_connect (int sockfd, struct sockaddr *addr, int addrlen); + +#ifdef HAVE_FOPENCOOKIE +/* We have to implement funopen in terms of glibc's fopencookie. */ +FILE *_assuan_funopen(void *cookie, + cookie_read_function_t *readfn, + cookie_write_function_t *writefn, + cookie_seek_function_t *seekfn, + cookie_close_function_t *closefn); +#define funopen(a,r,w,s,c) _assuan_funopen ((a), (r), (w), (s), (c)) +#endif /*HAVE_FOPENCOOKIE*/ + +/* Prototypes for replacement functions. */ +#ifndef HAVE_MEMRCHR +void *memrchr (const void *block, int c, size_t size); +#endif +#ifndef HAVE_STPCPY +char *stpcpy (char *dest, const char *src); +#endif +#ifndef HAVE_SETENV +#define setenv _assuan_setenv +#define unsetenv _assuan_unsetenv +#define clearenv _assuan_clearenv +int setenv (const char *name, const char *value, int replace); +#endif +#ifndef HAVE_PUTC_UNLOCKED +int putc_unlocked (int c, FILE *stream); +#endif + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) +#define DIMof(type,member) DIM(((type *)0)->member) + + +#endif /*ASSUAN_DEFS_H*/ diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-handler.c b/libkdenetwork/libgpgme-copy/assuan/assuan-handler.c new file mode 100644 index 000000000..866db2259 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-handler.c @@ -0,0 +1,774 @@ +/* assuan-handler.c - dispatch commands + * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "assuan-defs.h" + + + +#define spacep(p) (*(p) == ' ' || *(p) == '\t') +#define digitp(a) ((a) >= '0' && (a) <= '9') + +static int my_strcasecmp (const char *a, const char *b); + + + +static int +dummy_handler (assuan_context_t ctx, char *line) +{ + return set_error (ctx, Server_Fault, "no handler registered"); +} + + +static int +std_handler_nop (assuan_context_t ctx, char *line) +{ + return 0; /* okay */ +} + +static int +std_handler_cancel (assuan_context_t ctx, char *line) +{ + if (ctx->cancel_notify_fnc) + ctx->cancel_notify_fnc (ctx); + return set_error (ctx, Not_Implemented, NULL); +} + +static int +std_handler_option (assuan_context_t ctx, char *line) +{ + char *key, *value, *p; + + for (key=line; spacep (key); key++) + ; + if (!*key) + return set_error (ctx, Syntax_Error, "argument required"); + if (*key == '=') + return set_error (ctx, Syntax_Error, "no option name given"); + for (value=key; *value && !spacep (value) && *value != '='; value++) + ; + if (*value) + { + if (spacep (value)) + *value++ = 0; /* terminate key */ + for (; spacep (value); value++) + ; + if (*value == '=') + { + *value++ = 0; /* terminate key */ + for (; spacep (value); value++) + ; + if (!*value) + return set_error (ctx, Syntax_Error, "option argument expected"); + } + if (*value) + { + for (p = value + strlen(value) - 1; p > value && spacep (p); p--) + ; + if (p > value) + *++p = 0; /* strip trailing spaces */ + } + } + + if (*key == '-' && key[1] == '-' && key[2]) + key += 2; /* the double dashes are optional */ + if (*key == '-') + return set_error (ctx, Syntax_Error, + "option should not begin with one dash"); + + if (ctx->option_handler_fnc) + return ctx->option_handler_fnc (ctx, key, value); + return 0; +} + +static int +std_handler_bye (assuan_context_t ctx, char *line) +{ + if (ctx->bye_notify_fnc) + ctx->bye_notify_fnc (ctx); + assuan_close_input_fd (ctx); + assuan_close_output_fd (ctx); + return -1; /* pretty simple :-) */ +} + +static int +std_handler_auth (assuan_context_t ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +static int +std_handler_reset (assuan_context_t ctx, char *line) +{ + if (ctx->reset_notify_fnc) + ctx->reset_notify_fnc (ctx); + assuan_close_input_fd (ctx); + assuan_close_output_fd (ctx); + _assuan_uds_close_fds (ctx); + return 0; +} + +static int +std_handler_end (assuan_context_t ctx, char *line) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +assuan_error_t +assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd) +{ + char *endp; + + if ( (strncmp (line, "FD", 2) && strncmp (line, "fd", 2)) + || (line[2] != '=' && line[2] != '\0')) + return set_error (ctx, Syntax_Error, "FD[=<n>] expected"); + line += 2; + if (*line == '=') + { + line ++; + if (!digitp (*line)) + return set_error (ctx, Syntax_Error, "number required"); + *rfd = strtoul (line, &endp, 10); + /* Remove that argument so that a notify handler won't see it. */ + memset (line, ' ', endp? (endp-line):strlen(line)); + + if (*rfd == ctx->inbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as inbound fd"); + if (*rfd == ctx->outbound.fd) + return set_error (ctx, Parameter_Conflict, "fd same as outbound fd"); + return 0; + } + else + /* Our peer has sent the file descriptor. */ + return assuan_receivefd (ctx, rfd); +} + +/* Format is INPUT FD=<n> */ +static int +std_handler_input (assuan_context_t ctx, char *line) +{ + int rc, fd; + + rc = assuan_command_parse_fd (ctx, line, &fd); + if (rc) + return rc; + ctx->input_fd = fd; + if (ctx->input_notify_fnc) + ctx->input_notify_fnc (ctx, line); + return 0; +} + +/* Format is OUTPUT FD=<n> */ +static int +std_handler_output (assuan_context_t ctx, char *line) +{ + int rc, fd; + + rc = assuan_command_parse_fd (ctx, line, &fd); + if (rc) + return rc; + ctx->output_fd = fd; + if (ctx->output_notify_fnc) + ctx->output_notify_fnc (ctx, line); + return 0; +} + + + + + +/* This is a table with the standard commands and handler for them. + The table is used to initialize a new context and associate strings + with default handlers */ +static struct { + const char *name; + int (*handler)(assuan_context_t, char *line); + int always; /* always initialize this command */ +} std_cmd_table[] = { + { "NOP", std_handler_nop, 1 }, + { "CANCEL", std_handler_cancel, 1 }, + { "OPTION", std_handler_option, 1 }, + { "BYE", std_handler_bye, 1 }, + { "AUTH", std_handler_auth, 1 }, + { "RESET", std_handler_reset, 1 }, + { "END", std_handler_end, 1 }, + + { "INPUT", std_handler_input }, + { "OUTPUT", std_handler_output }, + { "OPTION", std_handler_option, 1 }, + { NULL } +}; + + +/** + * assuan_register_command: + * @ctx: the server context + * @cmd_name: A string with the command name + * @handler: The handler function to be called or NULL to use a default + * handler. + * + * Register a handler to be used for a given command. Note that + * several default handlers are already regsitered with a new context. + * This function however allows to override them. + * + * Return value: 0 on success or an error code + **/ +int +assuan_register_command (assuan_context_t ctx, + const char *cmd_name, + int (*handler)(assuan_context_t, char *)) +{ + int i; + const char *s; + + if (cmd_name && !*cmd_name) + cmd_name = NULL; + + if (!cmd_name) + return _assuan_error (ASSUAN_Invalid_Value); + + if (!handler) + { /* find a default handler. */ + for (i=0; (s=std_cmd_table[i].name) && strcmp (cmd_name, s); i++) + ; + if (!s) + { /* Try again but case insensitive. */ + for (i=0; (s=std_cmd_table[i].name) + && my_strcasecmp (cmd_name, s); i++) + ; + } + if (s) + handler = std_cmd_table[i].handler; + if (!handler) + handler = dummy_handler; /* Last resort is the dummy handler. */ + } + + if (!ctx->cmdtbl) + { + ctx->cmdtbl_size = 50; + ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl); + if (!ctx->cmdtbl) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->cmdtbl_used = 0; + } + else if (ctx->cmdtbl_used >= ctx->cmdtbl_size) + { + struct cmdtbl_s *x; + + x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x); + if (!x) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->cmdtbl = x; + ctx->cmdtbl_size += 50; + } + + ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name; + ctx->cmdtbl[ctx->cmdtbl_used].handler = handler; + ctx->cmdtbl_used++; + return 0; +} + +int +assuan_register_post_cmd_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, int)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->post_cmd_notify_fnc = fnc; + return 0; +} + +int +assuan_register_bye_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->bye_notify_fnc = fnc; + return 0; +} + +int +assuan_register_reset_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->reset_notify_fnc = fnc; + return 0; +} + +int +assuan_register_cancel_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->cancel_notify_fnc = fnc; + return 0; +} + +int +assuan_register_option_handler (assuan_context_t ctx, + int (*fnc)(assuan_context_t, + const char*, const char*)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->option_handler_fnc = fnc; + return 0; +} + +int +assuan_register_input_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->input_notify_fnc = fnc; + return 0; +} + +int +assuan_register_output_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + ctx->output_notify_fnc = fnc; + return 0; +} + + +/* Helper to register the standards commands */ +int +_assuan_register_std_commands (assuan_context_t ctx) +{ + int i, rc; + + for (i=0; std_cmd_table[i].name; i++) + { + if (std_cmd_table[i].always) + { + rc = assuan_register_command (ctx, std_cmd_table[i].name, NULL); + if (rc) + return rc; + } + } + return 0; +} + + + +/* Process the special data lines. The "D " has already been removed + from the line. As all handlers this function may modify the line. */ +static int +handle_data_line (assuan_context_t ctx, char *line, int linelen) +{ + return set_error (ctx, Not_Implemented, NULL); +} + +/* like ascii_strcasecmp but assume that B is already uppercase */ +static int +my_strcasecmp (const char *a, const char *b) +{ + if (a == b) + return 0; + + for (; *a && *b; a++, b++) + { + if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b) + break; + } + return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b); +} + +/* Parse the line, break out the command, find it in the command + table, remove leading and white spaces from the arguments, call the + handler with the argument line and return the error */ +static int +dispatch_command (assuan_context_t ctx, char *line, int linelen) +{ + char *p; + const char *s; + int shift, i; + + if (*line == 'D' && line[1] == ' ') /* divert to special handler */ + return handle_data_line (ctx, line+2, linelen-2); + + for (p=line; *p && *p != ' ' && *p != '\t'; p++) + ; + if (p==line) + return set_error (ctx, Syntax_Error, "leading white-space"); + if (*p) + { /* Skip over leading WS after the keyword */ + *p++ = 0; + while ( *p == ' ' || *p == '\t') + p++; + } + shift = p - line; + + for (i=0; (s=ctx->cmdtbl[i].name); i++) + { + if (!strcmp (line, s)) + break; + } + if (!s) + { /* and try case insensitive */ + for (i=0; (s=ctx->cmdtbl[i].name); i++) + { + if (!my_strcasecmp (line, s)) + break; + } + } + if (!s) + return set_error (ctx, Unknown_Command, NULL); + line += shift; + linelen -= shift; + +/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */ + return ctx->cmdtbl[i].handler (ctx, line); +} + + + + +static int +process_request (assuan_context_t ctx) +{ + int rc; + + if (ctx->in_inquire) + return _assuan_error (ASSUAN_Nested_Commands); + + rc = _assuan_read_line (ctx); + if (rc) + return rc; + if (*ctx->inbound.line == '#' || !ctx->inbound.linelen) + return 0; /* comment line - ignore */ + + ctx->outbound.data.error = 0; + ctx->outbound.data.linelen = 0; + /* dispatch command and return reply */ + rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen); + /* check from data write errors */ + if (ctx->outbound.data.fp) + { /* Flush the data lines */ + fclose (ctx->outbound.data.fp); + ctx->outbound.data.fp = NULL; + if (!rc && ctx->outbound.data.error) + rc = ctx->outbound.data.error; + } + else /* flush any data send w/o using the data fp */ + { + assuan_send_data (ctx, NULL, 0); + if (!rc && ctx->outbound.data.error) + rc = ctx->outbound.data.error; + } + /* Error handling */ + if (!rc) + { + rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK"); + } + else if (err_is_eof (rc)) + { /* No error checking because the peer may have already disconnect. */ + assuan_write_line (ctx, "OK closing connection"); + ctx->finish_handler (ctx); + } + else + { + char errline[300]; + + if (rc < 100) + sprintf (errline, "ERR %d server fault (%.50s)", + _assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc)); + else + { + const char *text = ctx->err_no == rc? ctx->err_str:NULL; + +#if defined(__GNUC__) && defined(__ELF__) + /* If we have weak symbol support we try to use the error + strings from libgpg-error without creating a dependency. + They are used for debugging purposes only, so there is no + problem if they are not available. We need to make sure + that we are using ELF because only this guarantees that + weak symbol support is available in case GNU ld is not + used. It seems that old gcc versions don't implement the + weak attribute properly but it works with the weak + pragma. */ + + unsigned int source, code; + + int gpg_strerror_r (unsigned int err, char *buf, size_t buflen) + __attribute__ ((weak)); + const char *gpg_strsource (unsigned int err) + __attribute__ ((weak)); +#if !defined(HAVE_W32_SYSTEM) && __GNUC__ < 3 +#pragma weak gpg_strerror_r +#pragma weak gpg_strsource +#endif + + source = ((rc >> 24) & 0xff); + code = (rc & 0x00ffffff); + if (source && gpg_strsource && gpg_strerror_r) + { + /* Assume this is an libgpg-error. */ + char ebuf[50]; + + gpg_strerror_r (rc, ebuf, sizeof ebuf ); + sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s", + rc, + ebuf, + gpg_strsource (rc), + text? " - ":"", text?text:""); + } + else +#endif /* __GNUC__ && __ELF__ */ + sprintf (errline, "ERR %d %.50s%s%.100s", + rc, assuan_strerror (rc), text? " - ":"", text?text:""); + } + rc = assuan_write_line (ctx, errline); + } + + if (ctx->post_cmd_notify_fnc) + ctx->post_cmd_notify_fnc (ctx, rc); + + ctx->confidential = 0; + if (ctx->okay_line) + { + xfree (ctx->okay_line); + ctx->okay_line = NULL; + } + return rc; +} + +/** + * assuan_process: + * @ctx: assuan context + * + * This function is used to handle the assuan protocol after a + * connection has been established using assuan_accept(). This is the + * main protocol handler. + * + * Return value: 0 on success or an error code if the assuan operation + * failed. Note, that no error is returned for operational errors. + **/ +int +assuan_process (assuan_context_t ctx) +{ + int rc; + + do { + rc = process_request (ctx); + } while (!rc); + + if (err_is_eof (rc)) + rc = 0; + + return rc; +} + + +/** + * assuan_process_next: + * @ctx: Assuan context + * + * Same as assuan_process() but the user has to provide the outer + * loop. He should loop as long as the return code is zero and stop + * otherwise; -1 is regular end. + * + * See also: assuan_get_active_fds() + * Return value: -1 for end of server, 0 on success or an error code + **/ +int +assuan_process_next (assuan_context_t ctx) +{ + return process_request (ctx); +} + + +/** + * assuan_get_active_fds: + * @ctx: Assuan context + * @what: 0 for read fds, 1 for write fds + * @fdarray: Caller supplied array to store the FDs + * @fdarraysize: size of that array + * + * Return all active filedescriptors for the given context. This + * function can be used to select on the fds and call + * assuan_process_next() if there is an active one. The first fd in + * the array is the one used for the command connection. + * + * Note, that write FDs are not yet supported. + * + * Return value: number of FDs active and put into @fdarray or -1 on + * error which is most likely a too small fdarray. + **/ +int +assuan_get_active_fds (assuan_context_t ctx, int what, + int *fdarray, int fdarraysize) +{ + int n = 0; + + if (!ctx || fdarraysize < 2 || what < 0 || what > 1) + return -1; + + if (!what) + { + if (ctx->inbound.fd != -1) + fdarray[n++] = ctx->inbound.fd; + } + else + { + if (ctx->outbound.fd != -1) + fdarray[n++] = ctx->outbound.fd; + if (ctx->outbound.data.fp) + fdarray[n++] = fileno (ctx->outbound.data.fp); + } + + return n; +} + + +/* Two simple wrappers to make the expected function types match. */ +#ifdef HAVE_FUNOPEN +static int +fun1_cookie_write (void *cookie, const char *buffer, int orig_size) +{ + return _assuan_cookie_write_data (cookie, buffer, orig_size); +} +#endif /*HAVE_FUNOPEN*/ +#ifdef HAVE_FOPENCOOKIE +static ssize_t +fun2_cookie_write (void *cookie, const char *buffer, size_t orig_size) +{ + return _assuan_cookie_write_data (cookie, buffer, orig_size); +} +#endif /*HAVE_FOPENCOOKIE*/ + +/* Return a FP to be used for data output. The FILE pointer is valid + until the end of a handler. So a close is not needed. Assuan does + all the buffering needed to insert the status line as well as the + required line wappping and quoting for data lines. + + We use GNU's custom streams here. There should be an alternative + implementaion for systems w/o a glibc, a simple implementation + could use a child process */ +FILE * +assuan_get_data_fp (assuan_context_t ctx) +{ +#if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN) + if (ctx->outbound.data.fp) + return ctx->outbound.data.fp; + +#ifdef HAVE_FUNOPEN + ctx->outbound.data.fp = funopen (ctx, 0, fun1_cookie_write, + 0, _assuan_cookie_write_flush); +#else + ctx->outbound.data.fp = funopen (ctx, 0, fun2_cookie_write, + 0, _assuan_cookie_write_flush); +#endif + + ctx->outbound.data.error = 0; + return ctx->outbound.data.fp; +#else + errno = ENOSYS; + return NULL; +#endif +} + + +/* Set the text used for the next OK reponse. This string is + automatically reset to NULL after the next command. */ +assuan_error_t +assuan_set_okay_line (assuan_context_t ctx, const char *line) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + if (!line) + { + xfree (ctx->okay_line); + ctx->okay_line = NULL; + } + else + { + /* FIXME: we need to use gcry_is_secure() to test whether + we should allocate the entire line in secure memory */ + char *buf = xtrymalloc (3+strlen(line)+1); + if (!buf) + return _assuan_error (ASSUAN_Out_Of_Core); + strcpy (buf, "OK "); + strcpy (buf+3, line); + xfree (ctx->okay_line); + ctx->okay_line = buf; + } + return 0; +} + + + +assuan_error_t +assuan_write_status (assuan_context_t ctx, + const char *keyword, const char *text) +{ + char buffer[256]; + char *helpbuf; + size_t n; + assuan_error_t ae; + + if ( !ctx || !keyword) + return _assuan_error (ASSUAN_Invalid_Value); + if (!text) + text = ""; + + n = 2 + strlen (keyword) + 1 + strlen (text) + 1; + if (n < sizeof (buffer)) + { + strcpy (buffer, "S "); + strcat (buffer, keyword); + if (*text) + { + strcat (buffer, " "); + strcat (buffer, text); + } + ae = assuan_write_line (ctx, buffer); + } + else if ( (helpbuf = xtrymalloc (n)) ) + { + strcpy (helpbuf, "S "); + strcat (helpbuf, keyword); + if (*text) + { + strcat (helpbuf, " "); + strcat (helpbuf, text); + } + ae = assuan_write_line (ctx, helpbuf); + xfree (helpbuf); + } + else + ae = 0; + return ae; +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-inquire.c b/libkdenetwork/libgpgme-copy/assuan/assuan-inquire.c new file mode 100644 index 000000000..d8c52d09a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-inquire.c @@ -0,0 +1,241 @@ +/* assuan-inquire.c - handle inquire stuff + * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "assuan-defs.h" + +#define digitp(a) ((a) >= '0' && (a) <= '9') +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) + + +struct membuf +{ + size_t len; + size_t size; + char *buf; + int out_of_core; + int too_large; + size_t maxlen; +}; + + + +/* A simple implemnation of a dynamic buffer. Use init_membuf() to + create a buffer, put_membuf to append bytes and get_membuf to + release and return the buffer. Allocation errors are detected but + only returned at the final get_membuf(), this helps not to clutter + the code with out of core checks. */ + +static void +init_membuf (struct membuf *mb, int initiallen, size_t maxlen) +{ + mb->len = 0; + mb->size = initiallen; + mb->out_of_core = 0; + mb->too_large = 0; + mb->maxlen = maxlen; + /* we need to allocate one byte more for get_membuf */ + mb->buf = xtrymalloc (initiallen+1); + if (!mb->buf) + mb->out_of_core = 1; +} + +static void +put_membuf (struct membuf *mb, const void *buf, size_t len) +{ + if (mb->out_of_core || mb->too_large) + return; + + if (mb->maxlen && mb->len + len > mb->maxlen) + { + mb->too_large = 1; + return; + } + + if (mb->len + len >= mb->size) + { + char *p; + + mb->size += len + 1024; + /* we need to allocate one byte more for get_membuf */ + p = xtryrealloc (mb->buf, mb->size+1); + if (!p) + { + mb->out_of_core = 1; + return; + } + mb->buf = p; + } + memcpy (mb->buf + mb->len, buf, len); + mb->len += len; +} + +static void * +get_membuf (struct membuf *mb, size_t *len) +{ + char *p; + + if (mb->out_of_core || mb->too_large) + { + xfree (mb->buf); + mb->buf = NULL; + return NULL; + } + + mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */ + p = mb->buf; + *len = mb->len; + mb->buf = NULL; + mb->out_of_core = 1; /* don't allow a reuse */ + return p; +} + +static void +free_membuf (struct membuf *mb) +{ + xfree (mb->buf); + mb->buf = NULL; +} + + +/** + * assuan_inquire: + * @ctx: An assuan context + * @keyword: The keyword used for the inquire + * @r_buffer: Returns an allocated buffer + * @r_length: Returns the length of this buffer + * @maxlen: If not 0, the size limit of the inquired data. + * + * A Server may use this to Send an inquire. r_buffer, r_length and + * maxlen may all be NULL/0 to indicate that no real data is expected. + * + * Return value: 0 on success or an ASSUAN error code + **/ +assuan_error_t +assuan_inquire (assuan_context_t ctx, const char *keyword, + unsigned char **r_buffer, size_t *r_length, size_t maxlen) +{ + assuan_error_t rc; + struct membuf mb; + char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */ + unsigned char *line, *p; + int linelen; + int nodataexpected; + + if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf))) + return _assuan_error (ASSUAN_Invalid_Value); + nodataexpected = !r_buffer && !r_length && !maxlen; + if (!nodataexpected && (!r_buffer || !r_length)) + return _assuan_error (ASSUAN_Invalid_Value); + if (!ctx->is_server) + return _assuan_error (ASSUAN_Not_A_Server); + if (ctx->in_inquire) + return _assuan_error (ASSUAN_Nested_Commands); + + ctx->in_inquire = 1; + if (nodataexpected) + memset (&mb, 0, sizeof mb); /* avoid compiler warnings */ + else + init_membuf (&mb, maxlen? maxlen:1024, maxlen); + + strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword); + rc = assuan_write_line (ctx, cmdbuf); + if (rc) + goto leave; + + for (;;) + { + do + { + rc = _assuan_read_line (ctx); + if (rc) + goto leave; + line = (unsigned char *) ctx->inbound.line; + linelen = ctx->inbound.linelen; + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N') + { + rc = _assuan_error (ASSUAN_Canceled); + goto leave; + } + if (line[0] != 'D' || line[1] != ' ' || nodataexpected) + { + rc = _assuan_error (ASSUAN_Unexpected_Command); + goto leave; + } + if (linelen < 3) + continue; + line += 2; + linelen -= 2; + + p = line; + while (linelen) + { + for (;linelen && *p != '%'; linelen--, p++) + ; + put_membuf (&mb, line, p-line); + if (linelen > 2) + { /* handle escaping */ + unsigned char tmp[1]; + p++; + *tmp = xtoi_2 (p); + p += 2; + linelen -= 3; + put_membuf (&mb, tmp, 1); + } + line = p; + } + if (mb.too_large) + { + rc = _assuan_error (ASSUAN_Too_Much_Data); + goto leave; + } + } + + if (!nodataexpected) + { + *r_buffer = get_membuf (&mb, r_length); + if (!*r_buffer) + rc = _assuan_error (ASSUAN_Out_Of_Core); + } + + leave: + if (!nodataexpected) + free_membuf (&mb); + ctx->in_inquire = 0; + return rc; +} + + + + + + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-io.c b/libkdenetwork/libgpgme-copy/assuan/assuan-io.c new file mode 100644 index 000000000..d1f0d5e48 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-io.c @@ -0,0 +1,87 @@ +/* assuan-io.c - Wraps the read and write functions. + * Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <errno.h> +#ifdef HAVE_W32_SYSTEM +# include <windows.h> +#else +# include <sys/wait.h> +#endif + +#include "assuan-defs.h" + + +#ifndef HAVE_W32_SYSTEM +pid_t +_assuan_waitpid (pid_t pid, int *status, int options) +{ + return waitpid (pid, status, options); +} +#endif + + +ssize_t +_assuan_simple_read (assuan_context_t ctx, void *buffer, size_t size) +{ + return read (ctx->inbound.fd, buffer, size); +} + +ssize_t +_assuan_simple_write (assuan_context_t ctx, const void *buffer, size_t size) +{ + return write (ctx->outbound.fd, buffer, size); +} + + +ssize_t +_assuan_simple_sendmsg (assuan_context_t ctx, struct msghdr *msg) +{ +#ifdef HAVE_W32_SYSTEM + return _assuan_error (ASSUAN_Not_Implemented); +#else + int ret; + while ( (ret = sendmsg (ctx->outbound.fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#endif +} + + +ssize_t +_assuan_simple_recvmsg (assuan_context_t ctx, struct msghdr *msg) +{ +#ifdef HAVE_W32_SYSTEM + return _assuan_error (ASSUAN_Not_Implemented); +#else + int ret; + while ( (ret = recvmsg (ctx->inbound.fd, msg, 0)) == -1 && errno == EINTR) + ; + return ret; +#endif +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-listen.c b/libkdenetwork/libgpgme-copy/assuan/assuan-listen.c new file mode 100644 index 000000000..04db68ce0 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-listen.c @@ -0,0 +1,157 @@ +/* assuan-listen.c - Wait for a connection (server) + * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "assuan-defs.h" + +assuan_error_t +assuan_set_hello_line (assuan_context_t ctx, const char *line) +{ + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + if (!line) + { + xfree (ctx->hello_line); + ctx->hello_line = NULL; + } + else + { + char *buf = xtrymalloc (3+strlen(line)+1); + if (!buf) + return _assuan_error (ASSUAN_Out_Of_Core); + if (strchr (line, '\n')) + strcpy (buf, line); + else + { + strcpy (buf, "OK "); + strcpy (buf+3, line); + } + xfree (ctx->hello_line); + ctx->hello_line = buf; + } + return 0; +} + + +/** + * assuan_accept: + * @ctx: context + * + * Cancel any existing connection and wait for a connection from a + * client. The initial handshake is performed which may include an + * initial authentication or encryption negotiation. + * + * Return value: 0 on success or an error if the connection could for + * some reason not be established. + **/ +assuan_error_t +assuan_accept (assuan_context_t ctx) +{ + int rc; + const char *p, *pend; + + if (!ctx) + return _assuan_error (ASSUAN_Invalid_Value); + + if (ctx->pipe_mode > 1) + return -1; /* second invocation for pipemode -> terminate */ + ctx->finish_handler (ctx); + + rc = ctx->accept_handler (ctx); + if (rc) + return rc; + + /* Send the hello. */ + p = ctx->hello_line; + if (p && (pend = strchr (p, '\n'))) + { /* This is a multi line hello. Send all but the last line as + comments. */ + do + { + rc = _assuan_write_line (ctx, "# ", p, pend - p); + if (rc) + return rc; + p = pend + 1; + pend = strchr (p, '\n'); + } + while (pend); + rc = _assuan_write_line (ctx, "OK ", p, strlen (p)); + } + else if (p) + rc = assuan_write_line (ctx, p); + else + rc = assuan_write_line (ctx, "OK Pleased to meet you"); + if (rc) + return rc; + + if (ctx->pipe_mode) + ctx->pipe_mode = 2; + + return 0; +} + + + +int +assuan_get_input_fd (assuan_context_t ctx) +{ + return ctx? ctx->input_fd : -1; +} + + +int +assuan_get_output_fd (assuan_context_t ctx) +{ + return ctx? ctx->output_fd : -1; +} + + +/* Close the fd descriptor set by the command INPUT FD=n. We handle + this fd inside assuan so that we can do some initial checks */ +assuan_error_t +assuan_close_input_fd (assuan_context_t ctx) +{ + if (!ctx || ctx->input_fd == -1) + return _assuan_error (ASSUAN_Invalid_Value); + _assuan_close (ctx->input_fd); + ctx->input_fd = -1; + return 0; +} + +/* Close the fd descriptor set by the command OUTPUT FD=n. We handle + this fd inside assuan so that we can do some initial checks */ +assuan_error_t +assuan_close_output_fd (assuan_context_t ctx) +{ + if (!ctx || ctx->output_fd == -1) + return _assuan_error (ASSUAN_Invalid_Value); + + _assuan_close (ctx->output_fd); + ctx->output_fd = -1; + return 0; +} + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-logging.c b/libkdenetwork/libgpgme-copy/assuan/assuan-logging.c new file mode 100644 index 000000000..cfc3d846f --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-logging.c @@ -0,0 +1,241 @@ +/* assuan-logging.c - Default logging function. + * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef HAVE_W32_SYSTEM +#include <windows.h> +#endif /*HAVE_W32_SYSTEM*/ +#include <errno.h> +#include <ctype.h> + +#include "assuan-defs.h" + +static char prefix_buffer[80]; +static FILE *_assuan_log; +static int full_logging; + +void +_assuan_set_default_log_stream (FILE *fp) +{ + if (!_assuan_log) + { + _assuan_log = fp; + full_logging = !!getenv ("ASSUAN_FULL_LOGGING"); + } +} + +void +assuan_set_assuan_log_stream (FILE *fp) +{ + _assuan_log = fp; +} + + +/* Set the per context log stream. Also enable the default log stream + if it has not been set. */ +void +assuan_set_log_stream (assuan_context_t ctx, FILE *fp) +{ + if (ctx) + { + if (ctx->log_fp) + fflush (ctx->log_fp); + ctx->log_fp = fp; + _assuan_set_default_log_stream (fp); + } +} + + +FILE * +assuan_get_assuan_log_stream (void) +{ + return _assuan_log ? _assuan_log : stderr; +} + + +/* Set the prefix to be used for logging to TEXT or + resets it to the default if TEXT is NULL. */ +void +assuan_set_assuan_log_prefix (const char *text) +{ + if (text) + { + strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); + prefix_buffer[sizeof (prefix_buffer)-1] = 0; + } + else + *prefix_buffer = 0; +} + +const char * +assuan_get_assuan_log_prefix (void) +{ + return prefix_buffer; +} + + +void +_assuan_log_printf (const char *format, ...) +{ + va_list arg_ptr; + FILE *fp; + const char *prf; + int save_errno = errno; + + fp = assuan_get_assuan_log_stream (); + prf = assuan_get_assuan_log_prefix (); + if (*prf) + fprintf (fp, "%s[%u]: ", prf, (unsigned int)getpid ()); + + va_start (arg_ptr, format); + vfprintf (fp, format, arg_ptr ); + va_end (arg_ptr); + errno = save_errno; +} + + +/* Dump a possibly binary string (used for debugging). Distinguish + ascii text from binary and print it accordingly. This function + takes FILE pointer arg becuase logging may be enabled on a per + context basis. */ +void +_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length) +{ + const unsigned char *s; + int n; + + for (n=length,s=buffer; n; n--, s++) + if ((!isascii (*s) || iscntrl (*s) || !isprint (*s)) && !(*s >= 0x80)) + break; + + s = buffer; + if (!n && *s != '[') + fwrite (buffer, length, 1, fp); + else + { +#ifdef HAVE_FLOCKFILE + flockfile (fp); +#endif + putc_unlocked ('[', fp); + if ( length > 16 && !full_logging) + { + for (n=0; n < 12; n++, s++) + fprintf (fp, " %02x", *s); + fprintf (fp, " ...(%d bytes skipped)", (int)length - 12); + } + else + { + for (n=0; n < length; n++, s++) + fprintf (fp, " %02x", *s); + } + putc_unlocked (' ', fp); + putc_unlocked (']', fp); +#ifdef HAVE_FUNLOCKFILE + funlockfile (fp); +#endif + } +} + +/* Log a user supplied string. Escapes non-printable before + printing. */ +void +_assuan_log_sanitized_string (const char *string) +{ + const unsigned char *s = (const unsigned char *) string; + FILE *fp = assuan_get_assuan_log_stream (); + + if (! *s) + return; + +#ifdef HAVE_FLOCKFILE + flockfile (fp); +#endif + + for (; *s; s++) + { + int c = 0; + + switch (*s) + { + case '\r': + c = 'r'; + break; + + case '\n': + c = 'n'; + break; + + case '\f': + c = 'f'; + break; + + case '\v': + c = 'v'; + break; + + case '\b': + c = 'b'; + break; + + default: + if ((isascii (*s) && isprint (*s)) || (*s >= 0x80)) + putc_unlocked (*s, fp); + else + { + putc_unlocked ('\\', fp); + fprintf (fp, "x%02x", *s); + } + } + + if (c) + { + putc_unlocked ('\\', fp); + putc_unlocked (c, fp); + } + } + +#ifdef HAVE_FUNLOCKFILE + funlockfile (fp); +#endif +} + + + +#ifdef HAVE_W32_SYSTEM +const char * +_assuan_w32_strerror (int ec) +{ + static char strerr[256]; + + if (ec == -1) + ec = (int)GetLastError (); + FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, ec, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + strerr, sizeof (strerr)-1, NULL); + return strerr; +} +#endif /*HAVE_W32_SYSTEM*/ diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-connect.c b/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-connect.c new file mode 100644 index 000000000..8ee9c748b --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-connect.c @@ -0,0 +1,889 @@ +/* assuan-pipe-connect.c - Establish a pipe connection (client) + * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/wait.h> +#else +#include <windows.h> +#endif + +#include "assuan-defs.h" + +/* Hacks for Slowaris. */ +#ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +#endif +#ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +#endif + + +#ifdef _POSIX_OPEN_MAX +#define MAX_OPEN_FDS _POSIX_OPEN_MAX +#else +#define MAX_OPEN_FDS 20 +#endif + +#ifdef HAVE_W32_SYSTEM +/* We assume that a HANDLE can be represented by an int which should + be true for all i386 systems (HANDLE is defined as void *) and + these are the only systems for which Windows is available. Further + we assume that -1 denotes an invalid handle. */ +#define fd_to_handle(a) ((HANDLE)(a)) +#define handle_to_fd(a) ((int)(a)) +#define pid_to_handle(a) ((HANDLE)(a)) +#define handle_to_pid(a) ((int)(a)) +#endif /*HAVE_W32_SYSTEM*/ + + +/* This should be called to make sure that SIGPIPE gets ignored. */ +static void +fix_signals (void) +{ +#ifndef _ASSUAN_NO_FIXED_SIGNALS +#ifndef HAVE_DOSISH_SYSTEM /* No SIGPIPE for these systems. */ + static int fixed_signals; + + if (!fixed_signals) + { + struct sigaction act; + + sigaction (SIGPIPE, NULL, &act); + if (act.sa_handler == SIG_DFL) + { + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGPIPE, &act, NULL); + } + fixed_signals = 1; + /* FIXME: This is not MT safe */ + } +#endif /*HAVE_DOSISH_SYSTEM*/ +#endif /*!_ASSUAN_NO_FIXED_SIGNALS*/ +} + + +#ifndef HAVE_W32_SYSTEM +static int +writen (int fd, const char *buffer, size_t length) +{ + while (length) + { + int nwritten = write (fd, buffer, length); + + if (nwritten < 0) + { + if (errno == EINTR) + continue; + return -1; /* write error */ + } + length -= nwritten; + buffer += nwritten; + } + return 0; /* okay */ +} +#endif + +static int +do_finish (assuan_context_t ctx) +{ + if (ctx->inbound.fd != -1) + { + _assuan_close (ctx->inbound.fd); + if (ctx->inbound.fd == ctx->outbound.fd) + ctx->outbound.fd = -1; + ctx->inbound.fd = -1; + } + if (ctx->outbound.fd != -1) + { + _assuan_close (ctx->outbound.fd); + ctx->outbound.fd = -1; + } + if (ctx->pid != -1 && ctx->pid) + { +#ifndef HAVE_W32_SYSTEM +#ifndef _ASSUAN_USE_DOUBLE_FORK + if (!ctx->flags.no_waitpid) + _assuan_waitpid (ctx->pid, NULL, 0); + ctx->pid = -1; +#endif +#endif /*!HAVE_W32_SYSTEM*/ + } + return 0; +} + +static void +do_deinit (assuan_context_t ctx) +{ + do_finish (ctx); +} + + +/* Helper for pipe_connect. */ +static assuan_error_t +initial_handshake (assuan_context_t *ctx) +{ + int okay, off; + assuan_error_t err; + + err = _assuan_read_from_server (*ctx, &okay, &off); + if (err) + _assuan_log_printf ("can't connect server: %s\n", + assuan_strerror (err)); + else if (okay != 1) + { + _assuan_log_printf ("can't connect server: `%s'\n", + (*ctx)->inbound.line); + err = _assuan_error (ASSUAN_Connect_Failed); + } + + if (err) + { + assuan_disconnect (*ctx); + *ctx = NULL; + } + return err; +} + + +#ifndef HAVE_W32_SYSTEM +#define pipe_connect pipe_connect_unix +/* Unix version of the pipe connection code. We use an extra macro to + make ChangeLog entries easier. */ +static assuan_error_t +pipe_connect_unix (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + assuan_error_t err; + int rp[2]; + int wp[2]; + char mypidstr[50]; + + if (!ctx || !name || !argv || !argv[0]) + return _assuan_error (ASSUAN_Invalid_Value); + + fix_signals (); + + sprintf (mypidstr, "%lu", (unsigned long)getpid ()); + + if (pipe (rp) < 0) + return _assuan_error (ASSUAN_General_Error); + + if (pipe (wp) < 0) + { + close (rp[0]); + close (rp[1]); + return _assuan_error (ASSUAN_General_Error); + } + + err = _assuan_new_context (ctx); + if (err) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + return err; + } + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ + (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ + (*ctx)->deinit_handler = do_deinit; + (*ctx)->finish_handler = do_finish; + + /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID + stored here is actually soon useless. */ + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (rp[0]); + close (rp[1]); + close (wp[0]); + close (wp[1]); + _assuan_release_context (*ctx); + return _assuan_error (ASSUAN_General_Error); + } + + if ((*ctx)->pid == 0) + { +#ifdef _ASSUAN_USE_DOUBLE_FORK + pid_t pid; + + if ((pid = fork ()) == 0) +#endif + { + int i, n; + char errbuf[512]; + int *fdp; + + if (atfork) + atfork (atforkvalue, 0); + + /* Dup handles to stdin/stdout. */ + if (rp[1] != STDOUT_FILENO) + { + if (dup2 (rp[1], STDOUT_FILENO) == -1) + { + _assuan_log_printf ("dup2 failed in child: %s\n", + strerror (errno)); + _exit (4); + } + } + if (wp[0] != STDIN_FILENO) + { + if (dup2 (wp[0], STDIN_FILENO) == -1) + { + _assuan_log_printf ("dup2 failed in child: %s\n", + strerror (errno)); + _exit (4); + } + } + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + int fd = open ("/dev/null", O_WRONLY); + if (fd == -1) + { + _assuan_log_printf ("can't open `/dev/null': %s\n", + strerror (errno)); + _exit (4); + } + if (dup2 (fd, STDERR_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n", + strerror (errno)); + _exit (4); + } + } + + + /* Close all files which will not be duped and are not in the + fd_child_list. */ + n = sysconf (_SC_OPEN_MAX); + if (n < 0) + n = MAX_OPEN_FDS; + for (i=0; i < n; i++) + { + if ( i == STDIN_FILENO || i == STDOUT_FILENO + || i == STDERR_FILENO) + continue; + fdp = fd_child_list; + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1)) + close(i); + } + errno = 0; + + /* We store our parents pid in the environment so that the + execed assuan server is able to read the actual pid of the + client. The server can't use getppid because it might have + been double forked before the assuan server has been + initialized. */ + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Make sure that we never pass a connection fd variable + when using a simple pipe. */ + unsetenv ("_assuan_connection_fd"); + + execv (name, (char *const *) argv); + /* oops - use the pipe to tell the parent about it */ + snprintf (errbuf, sizeof(errbuf)-1, + "ERR %d can't exec `%s': %.50s\n", + _assuan_error (ASSUAN_Problem_Starting_Server), + name, strerror (errno)); + errbuf[sizeof(errbuf)-1] = 0; + writen (1, errbuf, strlen (errbuf)); + _exit (4); + } +#ifdef _ASSUAN_USE_DOUBLE_FORK + if (pid == -1) + _exit (1); + else + _exit (0); +#endif + } + +#ifdef _ASSUAN_USE_DOUBLE_FORK + _assuan_waitpid ((*ctx)->pid, NULL, 0); + (*ctx)->pid = -1; +#endif + + close (rp[1]); + close (wp[0]); + + return initial_handshake (ctx); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +#ifndef HAVE_W32_SYSTEM +/* This function is similar to pipe_connect but uses a socketpair and + sets the I/O up to use sendmsg/recvmsg. */ +static assuan_error_t +socketpair_connect (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + assuan_error_t err; + int fds[2]; + char mypidstr[50]; + + if (!ctx + || (name && (!argv || !argv[0])) + || (!name && argv)) + return _assuan_error (ASSUAN_Invalid_Value); + + fix_signals (); + + sprintf (mypidstr, "%lu", (unsigned long)getpid ()); + + if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) ) + { + _assuan_log_printf ("socketpair failed: %s\n", strerror (errno)); + return _assuan_error (ASSUAN_General_Error); + } + + err = _assuan_new_context (ctx); + if (err) + { + close (fds[0]); + close (fds[1]); + return err; + } + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = fds[0]; + (*ctx)->outbound.fd = fds[0]; + _assuan_init_uds_io (*ctx); + (*ctx)->deinit_handler = _assuan_uds_deinit; + (*ctx)->finish_handler = do_finish; + + (*ctx)->pid = fork (); + if ((*ctx)->pid < 0) + { + close (fds[0]); + close (fds[1]); + _assuan_release_context (*ctx); + *ctx = NULL; + return _assuan_error (ASSUAN_General_Error); + } + + if ((*ctx)->pid == 0) + { +#ifdef _ASSUAN_USE_DOUBLE_FORK + pid_t pid; + + if ((pid = fork ()) == 0) +#endif + { + int fd, i, n; + char errbuf[512]; + int *fdp; + + if (atfork) + atfork (atforkvalue, 0); + + /* Connect stdin and stdout to /dev/null. */ + fd = open ("/dev/null", O_RDONLY); + if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + fd = open ("/dev/null", O_WRONLY); + if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + fd = open ("/dev/null", O_WRONLY); + if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1) + { + _assuan_log_printf ("dup2(dev/null) failed: %s\n", + strerror (errno)); + _exit (4); + } + } + + + /* Close all files which will not be duped, are not in the + fd_child_list and are not the connection fd. */ + n = sysconf (_SC_OPEN_MAX); + if (n < 0) + n = MAX_OPEN_FDS; + for (i=0; i < n; i++) + { + if ( i == STDIN_FILENO || i == STDOUT_FILENO + || i == STDERR_FILENO || i == fds[1]) + continue; + fdp = fd_child_list; + if (fdp) + { + while (*fdp != -1 && *fdp != i) + fdp++; + } + + if (!(fdp && *fdp != -1)) + close(i); + } + errno = 0; + + /* We store our parents pid in the environment so that the + execed assuan server is able to read the actual pid of the + client. The server can't use getppid becuase it might have + been double forked before the assuan server has been + initialized. */ + setenv ("_assuan_pipe_connect_pid", mypidstr, 1); + + /* Now set the environment variable used to convey the + connection's file descriptor. */ + sprintf (mypidstr, "%d", fds[1]); + if (setenv ("_assuan_connection_fd", mypidstr, 1)) + { + _assuan_log_printf ("setenv failed: %s\n", strerror (errno)); + _exit (4); + } + + if (!name && !argv) + { + /* No name and no args given, thus we don't do an exec + but continue the forked process. */ + _assuan_release_context (*ctx); + *ctx = NULL; + return 0; + } + + execv (name, (char *const *) argv); + /* oops - use the pipe to tell the parent about it */ + snprintf (errbuf, sizeof(errbuf)-1, + "ERR %d can't exec `%s': %.50s\n", + _assuan_error (ASSUAN_Problem_Starting_Server), + name, strerror (errno)); + errbuf[sizeof(errbuf)-1] = 0; + writen (fds[1], errbuf, strlen (errbuf)); + _exit (4); + } +#ifdef _ASSUAN_USE_DOUBLE_FORK + if (pid == -1) + _exit (1); + else + _exit (0); +#endif + } + + +#ifdef _ASSUAN_USE_DOUBLE_FORK + _assuan_waitpid ((*ctx)->pid, NULL, 0); + (*ctx)->pid = -1; +#endif + + close (fds[1]); + + return initial_handshake (ctx); +} +#endif /*!HAVE_W32_SYSTEM*/ + + + +#ifdef HAVE_W32_SYSTEM +/* Build a command line for use with W32's CreateProcess. On success + CMDLINE gets the address of a newly allocated string. */ +static int +build_w32_commandline (char * const *argv, char **cmdline) +{ + int i, n; + const char *s; + char *buf, *p; + + *cmdline = NULL; + n = 0; + for (i=0; (s=argv[i]); i++) + { + n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */ + for (; *s; s++) + if (*s == '\"') + n++; /* Need to double inner quotes. */ + } + n++; + + buf = p = xtrymalloc (n); + if (!buf) + return -1; + + for (i=0; argv[i]; i++) + { + if (i) + p = stpcpy (p, " "); + if (!*argv[i]) /* Empty string. */ + p = stpcpy (p, "\"\""); + else if (strpbrk (argv[i], " \t\n\v\f\"")) + { + p = stpcpy (p, "\""); + for (s=argv[i]; *s; s++) + { + *p++ = *s; + if (*s == '\"') + *p++ = *s; + } + *p++ = '\"'; + *p = 0; + } + else + p = stpcpy (p, argv[i]); + } + + *cmdline= buf; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +#ifdef HAVE_W32_SYSTEM +/* Create pipe where one end end is inheritable. */ +static int +create_inheritable_pipe (int filedes[2], int for_write) +{ + HANDLE r, w, h; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + if (!CreatePipe (&r, &w, &sec_attr, 0)) + { + _assuan_log_printf ("CreatePipe failed: %s\n", w32_strerror (-1)); + return -1; + } + + if (!DuplicateHandle (GetCurrentProcess(), for_write? r : w, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS )) + { + _assuan_log_printf ("DuplicateHandle failed: %s\n", w32_strerror (-1)); + CloseHandle (r); + CloseHandle (w); + return -1; + } + if (for_write) + { + CloseHandle (r); + r = h; + } + else + { + CloseHandle (w); + w = h; + } + + filedes[0] = handle_to_fd (r); + filedes[1] = handle_to_fd (w); + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +#ifdef HAVE_W32_SYSTEM +#define pipe_connect pipe_connect_w32 +/* W32 version of the pipe connection code. */ +static assuan_error_t +pipe_connect_w32 (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + assuan_error_t err; + int rp[2]; + int wp[2]; + char mypidstr[50]; + char *cmdline; + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = + { + NULL, /* Returns process handle. */ + 0, /* Returns primary thread handle. */ + 0, /* Returns pid. */ + 0 /* Returns tid. */ + }; + STARTUPINFO si; + int fd, *fdp; + HANDLE nullfd = INVALID_HANDLE_VALUE; + + if (!ctx || !name || !argv || !argv[0]) + return _assuan_error (ASSUAN_Invalid_Value); + + fix_signals (); + + sprintf (mypidstr, "%lu", (unsigned long)getpid ()); + + /* Build the command line. */ + if (build_w32_commandline (argv, &cmdline)) + return _assuan_error (ASSUAN_Out_Of_Core); + + /* Create thew two pipes. */ + if (create_inheritable_pipe (rp, 0)) + { + xfree (cmdline); + return _assuan_error (ASSUAN_General_Error); + } + + if (create_inheritable_pipe (wp, 1)) + { + CloseHandle (fd_to_handle (rp[0])); + CloseHandle (fd_to_handle (rp[1])); + xfree (cmdline); + return _assuan_error (ASSUAN_General_Error); + } + + + err = _assuan_new_context (ctx); + if (err) + { + CloseHandle (fd_to_handle (rp[0])); + CloseHandle (fd_to_handle (rp[1])); + CloseHandle (fd_to_handle (wp[0])); + CloseHandle (fd_to_handle (wp[1])); + xfree (cmdline); + return _assuan_error (ASSUAN_General_Error); + } + + (*ctx)->pipe_mode = 1; + (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */ + (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */ + (*ctx)->deinit_handler = do_deinit; + (*ctx)->finish_handler = do_finish; + + + /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env + variable. However this requires us to write a full environment + handler, because the strings are expected in sorted order. The + suggestion given in the MS Reference Library, to save the old + value, changeit, create proces and restore it, is not thread + safe. */ + + /* Start the process. */ + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = fd_to_handle (wp[0]); + si.hStdOutput = fd_to_handle (rp[1]); + + /* Dup stderr to /dev/null unless it is in the list of FDs to be + passed to the child. */ + fd = fileno (stderr); + fdp = fd_child_list; + if (fdp) + { + for (; *fdp != -1 && *fdp != fd; fdp++) + ; + } + if (!fdp || *fdp == -1) + { + nullfd = CreateFile ("nul", GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (nullfd == INVALID_HANDLE_VALUE) + { + _assuan_log_printf ("can't open `nul': %s\n", w32_strerror (-1)); + CloseHandle (fd_to_handle (rp[0])); + CloseHandle (fd_to_handle (rp[1])); + CloseHandle (fd_to_handle (wp[0])); + CloseHandle (fd_to_handle (wp[1])); + xfree (cmdline); + _assuan_release_context (*ctx); + return -1; + } + si.hStdError = nullfd; + } + else + si.hStdError = fd_to_handle (_get_osfhandle (fd)); + + + /* Note: We inherit all handles flagged as inheritable. This seems + to be a security flaw but there seems to be no way of selecting + handles to inherit. */ + /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */ + /* name, cmdline); */ + if (!CreateProcess (name, /* Program to start. */ + cmdline, /* Command line arguments. */ + &sec_attr, /* Process security attributes. */ + &sec_attr, /* Thread security attributes. */ + TRUE, /* Inherit handles. */ + (CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()) + | CREATE_SUSPENDED), /* Creation flags. */ + NULL, /* Environment. */ + NULL, /* Use current drive/directory. */ + &si, /* Startup information. */ + &pi /* Returns process information. */ + )) + { + _assuan_log_printf ("CreateProcess failed: %s\n", w32_strerror (-1)); + CloseHandle (fd_to_handle (rp[0])); + CloseHandle (fd_to_handle (rp[1])); + CloseHandle (fd_to_handle (wp[0])); + CloseHandle (fd_to_handle (wp[1])); + if (nullfd != INVALID_HANDLE_VALUE) + CloseHandle (nullfd); + xfree (cmdline); + _assuan_release_context (*ctx); + return _assuan_error (ASSUAN_General_Error); + } + xfree (cmdline); + cmdline = NULL; + if (nullfd != INVALID_HANDLE_VALUE) + { + CloseHandle (nullfd); + nullfd = INVALID_HANDLE_VALUE; + } + + CloseHandle (fd_to_handle (rp[1])); + CloseHandle (fd_to_handle (wp[0])); + + /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */ + /* " dwProcessID=%d dwThreadId=%d\n", */ + /* pi.hProcess, pi.hThread, */ + /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ + + ResumeThread (pi.hThread); + CloseHandle (pi.hThread); + (*ctx)->pid = 0; /* We don't use the PID. */ + CloseHandle (pi.hProcess); /* We don't need to wait for the process. */ + + return initial_handshake (ctx); +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* Connect to a server over a pipe, creating the assuan context and + returning it in CTX. The server filename is NAME, the argument + vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file + descriptors not to close in the child. */ +assuan_error_t +assuan_pipe_connect (assuan_context_t *ctx, const char *name, + const char *const argv[], int *fd_child_list) +{ + return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL); +} + + + +assuan_error_t +assuan_pipe_connect2 (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue) +{ + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); +} + + +/* Connect to a server over a full-duplex socket (i.e. created by + socketpair), creating the assuan context and returning it in CTX. + The server filename is NAME, the argument vector in ARGV. + FD_CHILD_LIST is a -1 terminated list of file descriptors not to + close in the child. ATFORK is called in the child right after the + fork; ATFORKVALUE is passed as the first argument and 0 is passed + as the second argument. The ATFORK function should only act if the + second value is 0. + + For now FLAGS may either take the value 0 to behave like + assuan_pipe_connect2 or 1 to enable the described full-duplex + socket behaviour. + + If NAME as well as ARGV are NULL, no exec is done but the same + process is continued. However all file descriptors are closed and + some special environment variables are set. To let the caller + detect whether the child or the parent continues, the child returns + a CTX of NULL. */ +assuan_error_t +assuan_pipe_connect_ext (assuan_context_t *ctx, + const char *name, const char *const argv[], + int *fd_child_list, + void (*atfork) (void *opaque, int reserved), + void *atforkvalue, unsigned int flags) +{ + if ((flags & 1)) + { +#ifdef HAVE_W32_SYSTEM + return _assuan_error (ASSUAN_Not_Implemented); +#else + return socketpair_connect (ctx, name, argv, fd_child_list, + atfork, atforkvalue); +#endif + } + else + return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue); +} + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-server.c b/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-server.c new file mode 100644 index 000000000..f88516143 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-pipe-server.c @@ -0,0 +1,187 @@ +/* assuan-pipe-server.c - Assuan server working over a pipe + * Copyright (C) 2001, 2002 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#ifdef HAVE_W32_SYSTEM +#include <windows.h> +#include <fcntl.h> +#endif + +#include "assuan-defs.h" + + +static void +deinit_pipe_server (assuan_context_t ctx) +{ + /* nothing to do for this simple server */ +} + +static int +accept_connection (assuan_context_t ctx) +{ + /* This is a NOP for a pipe server */ + return 0; +} + +static int +finish_connection (assuan_context_t ctx) +{ + /* This is a NOP for a pipe server */ + return 0; +} + +/* Create a new context. Note that the handlers are set up for a pipe + server/client - this way we don't need extra dummy functions */ +int +_assuan_new_context (assuan_context_t *r_ctx) +{ + static struct assuan_io io = { _assuan_simple_read, + _assuan_simple_write, + 0, 0 }; + + assuan_context_t ctx; + int rc; + + *r_ctx = NULL; + ctx = xtrycalloc (1, sizeof *ctx); + if (!ctx) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->input_fd = -1; + ctx->output_fd = -1; + + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + ctx->io = &io; + + ctx->listen_fd = -1; + /* Use the pipe server handler as a default. */ + ctx->deinit_handler = deinit_pipe_server; + ctx->accept_handler = accept_connection; + ctx->finish_handler = finish_connection; + + rc = _assuan_register_std_commands (ctx); + if (rc) + xfree (ctx); + else + *r_ctx = ctx; + return rc; +} + + +/* Returns true if atoi(S) denotes a valid socket. */ +static int +is_valid_socket (const char *s) +{ + struct stat buf; + + if ( fstat (atoi (s), &buf ) ) + return 0; + return S_ISSOCK (buf.st_mode); +} + + +int +assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]) +{ + int rc; + + rc = _assuan_new_context (r_ctx); + if (!rc) + { + assuan_context_t ctx = *r_ctx; + const char *s; + unsigned long ul; + + ctx->is_server = 1; +#ifdef HAVE_W32_SYSTEM + /* MS Windows has so many different types of handle that one + needs to tranlsate them at many place forth and back. Also + make sure that the fiel descriptos are in binary mode. */ + setmode (filedes[0], O_BINARY); + setmode (filedes[1], O_BINARY); + ctx->inbound.fd = _get_osfhandle (filedes[0]); + ctx->outbound.fd = _get_osfhandle (filedes[1]); +#else + s = getenv ("_assuan_connection_fd"); + if (s && *s && is_valid_socket (s) ) + { + /* Well, we are called with an bi-directional file + descriptor. Prepare for using sendmsg/recvmsg. In this + case we ignore the passed file descriptors. */ + ctx->inbound.fd = ctx->outbound.fd = atoi (s); + _assuan_init_uds_io (ctx); + ctx->deinit_handler = _assuan_uds_deinit; + } + else if (filedes && filedes[0] != -1 && filedes[1] != -1 ) + { + /* Standard pipe server. */ + ctx->inbound.fd = filedes[0]; + ctx->outbound.fd = filedes[1]; + } + else + { + _assuan_release_context (*r_ctx); + *r_ctx = NULL; + return ASSUAN_Problem_Starting_Server; + } +#endif + ctx->pipe_mode = 1; + + s = getenv ("_assuan_pipe_connect_pid"); + if (s && (ul=strtoul (s, NULL, 10)) && ul) + ctx->pid = (pid_t)ul; + else + ctx->pid = (pid_t)-1; + + } + return rc; +} + + +void +_assuan_release_context (assuan_context_t ctx) +{ + if (ctx) + { + xfree (ctx->hello_line); + xfree (ctx->okay_line); + xfree (ctx->cmdtbl); + xfree (ctx); + } +} + +void +assuan_deinit_server (assuan_context_t ctx) +{ + if (ctx) + { + /* We use this function pointer to avoid linking other server + when not needed but still allow for a generic deinit function. */ + ctx->deinit_handler (ctx); + ctx->deinit_handler = NULL; + _assuan_release_context (ctx); + } +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-socket-connect.c b/libkdenetwork/libgpgme-copy/assuan/assuan-socket-connect.c new file mode 100644 index 000000000..5953f1c33 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-socket-connect.c @@ -0,0 +1,184 @@ +/* assuan-socket-connect.c - Assuan socket based client + * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/socket.h> +#include <sys/un.h> +#else +#include <windows.h> +#endif + +#include "assuan-defs.h" + +/* Hacks for Slowaris. */ +#ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +#endif +#ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +#endif + +#ifndef SUN_LEN +# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + + +static int +do_finish (assuan_context_t ctx) +{ + if (ctx->inbound.fd != -1) + { + _assuan_close (ctx->inbound.fd); + } + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + return 0; +} + +static void +do_deinit (assuan_context_t ctx) +{ + do_finish (ctx); +} + + +/* Make a connection to the Unix domain socket NAME and return a new + Assuan context in CTX. SERVER_PID is currently not used but may + become handy in the future. */ +assuan_error_t +assuan_socket_connect (assuan_context_t *r_ctx, + const char *name, pid_t server_pid) +{ + return assuan_socket_connect_ext (r_ctx, name, server_pid, 0); +} + + +/* Make a connection to the Unix domain socket NAME and return a new + Assuan context in CTX. SERVER_PID is currently not used but may + become handy in the future. With flags set to 1 sendmsg and + recvmesg are used. */ +assuan_error_t +assuan_socket_connect_ext (assuan_context_t *r_ctx, + const char *name, pid_t server_pid, + unsigned int flags) +{ + static struct assuan_io io = { _assuan_simple_read, + _assuan_simple_write }; + + assuan_error_t err; + assuan_context_t ctx; + int fd; + struct sockaddr_un srvr_addr; + size_t len; + const char *s; + + if (!r_ctx || !name) + return _assuan_error (ASSUAN_Invalid_Value); + *r_ctx = NULL; + + /* We require that the name starts with a slash, so that we + eventually can reuse this function for other socket types. To + make things easier we allow an optional dirver prefix. */ + s = name; + if (*s && s[1] == ':') + s += 2; + if (*s != DIRSEP_C && *s != '/') + return _assuan_error (ASSUAN_Invalid_Value); + + if (strlen (name)+1 >= sizeof srvr_addr.sun_path) + return _assuan_error (ASSUAN_Invalid_Value); + + err = _assuan_new_context (&ctx); + if (err) + return err; + ctx->deinit_handler = ((flags&1))? _assuan_uds_deinit : do_deinit; + ctx->finish_handler = do_finish; + + fd = _assuan_sock_new (PF_LOCAL, SOCK_STREAM, 0); + if (fd == -1) + { + _assuan_log_printf ("can't create socket: %s\n", strerror (errno)); + _assuan_release_context (ctx); + return _assuan_error (ASSUAN_General_Error); + } + + memset (&srvr_addr, 0, sizeof srvr_addr); + srvr_addr.sun_family = AF_LOCAL; + strncpy (srvr_addr.sun_path, name, sizeof (srvr_addr.sun_path) - 1); + srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0; + len = SUN_LEN (&srvr_addr); + + + if (_assuan_sock_connect (fd, (struct sockaddr *) &srvr_addr, len) == -1) + { + _assuan_log_printf ("can't connect to `%s': %s\n", + name, strerror (errno)); + _assuan_release_context (ctx); + _assuan_close (fd); + return _assuan_error (ASSUAN_Connect_Failed); + } + + ctx->inbound.fd = fd; + ctx->outbound.fd = fd; + ctx->io = &io; + if ((flags&1)) + _assuan_init_uds_io (ctx); + + /* initial handshake */ + { + int okay, off; + + err = _assuan_read_from_server (ctx, &okay, &off); + if (err) + _assuan_log_printf ("can't connect to server: %s\n", + assuan_strerror (err)); + else if (okay != 1) + { + /*LOG ("can't connect to server: `");*/ + _assuan_log_sanitized_string (ctx->inbound.line); + fprintf (assuan_get_assuan_log_stream (), "'\n"); + err = _assuan_error (ASSUAN_Connect_Failed); + } + } + + if (err) + { + assuan_disconnect (ctx); + } + else + *r_ctx = ctx; + return 0; +} + + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-socket-server.c b/libkdenetwork/libgpgme-copy/assuan/assuan-socket-server.c new file mode 100644 index 000000000..45c227d6d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-socket-server.c @@ -0,0 +1,187 @@ +/* assuan-socket-server.c - Assuan socket based server + * Copyright (C) 2002 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/socket.h> +#include <sys/un.h> +#else +#include <windows.h> +#endif + +#include "assuan-defs.h" + +static struct assuan_io io = { _assuan_simple_read, + _assuan_simple_write }; + + +static int +accept_connection_bottom (assuan_context_t ctx) +{ + int fd = ctx->connected_fd; + + ctx->peercred.valid = 0; +#ifdef HAVE_SO_PEERCRED + { + struct ucred cr; + socklen_t cl = sizeof cr; + + if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl)) + { + ctx->peercred.pid = cr.pid; + ctx->peercred.uid = cr.uid; + ctx->peercred.gid = cr.gid; + ctx->peercred.valid = 1; + + /* This overrides any already set PID if the function returns + a valid one. */ + if (cr.pid != (pid_t)-1 && cr.pid) + ctx->pid = cr.pid; + } + } +#endif + + ctx->inbound.fd = fd; + ctx->inbound.eof = 0; + ctx->inbound.linelen = 0; + ctx->inbound.attic.linelen = 0; + ctx->inbound.attic.pending = 0; + + ctx->outbound.fd = fd; + ctx->outbound.data.linelen = 0; + ctx->outbound.data.error = 0; + + ctx->confidential = 0; + + return 0; +} + + +static int +accept_connection (assuan_context_t ctx) +{ + int fd; + struct sockaddr_un clnt_addr; + socklen_t len = sizeof clnt_addr; + + fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len ); + if (fd == -1) + { + ctx->os_errno = errno; + return _assuan_error (ASSUAN_Accept_Failed); + } + + ctx->connected_fd = fd; + return accept_connection_bottom (ctx); +} + +static int +finish_connection (assuan_context_t ctx) +{ + if (ctx->inbound.fd != -1) + { + _assuan_close (ctx->inbound.fd); + } + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + return 0; +} + + +static void +deinit_socket_server (assuan_context_t ctx) +{ + finish_connection (ctx); +} + +/* Initialize a server for the socket LISTEN_FD which has already be + put into listen mode */ +int +assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd) +{ + return assuan_init_socket_server_ext (r_ctx, listen_fd, 0); +} + +/* Initialize a server using the already accepted socket FD. This + fucntion is deprecated. */ +int +assuan_init_connected_socket_server (assuan_context_t *r_ctx, int fd) +{ + return assuan_init_socket_server_ext (r_ctx, fd, 2); +} + + +/* + Flag bits: 0 - use sendmsg/recvmsg to allow descriptor passing + 1 - FD has already been accepted. +*/ +int +assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, + unsigned int flags) +{ + assuan_context_t ctx; + int rc; + + *r_ctx = NULL; + ctx = xtrycalloc (1, sizeof *ctx); + if (!ctx) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->is_server = 1; + if ((flags & 2)) + ctx->pipe_mode = 1; /* We want a second accept to indicate EOF. */ + ctx->input_fd = -1; + ctx->output_fd = -1; + + ctx->inbound.fd = -1; + ctx->outbound.fd = -1; + + if ((flags & 2)) + { + ctx->listen_fd = -1; + ctx->connected_fd = fd; + } + else + { + ctx->listen_fd = fd; + ctx->connected_fd = -1; + } + ctx->deinit_handler = (flags & 1)? _assuan_uds_deinit:deinit_socket_server; + ctx->accept_handler = ((flags & 2) + ? accept_connection_bottom + : accept_connection); + ctx->finish_handler = finish_connection; + + ctx->io = &io; + if ((flags & 1)) + _assuan_init_uds_io (ctx); + + rc = _assuan_register_std_commands (ctx); + if (rc) + xfree (ctx); + else + *r_ctx = ctx; + return rc; +} diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-socket.c b/libkdenetwork/libgpgme-copy/assuan/assuan-socket.c new file mode 100644 index 000000000..6aa570896 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-socket.c @@ -0,0 +1,148 @@ +/* assuan-socket.c + * Copyright (C) 2004, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdio.h> +#ifdef HAVE_W32_SYSTEM +#include <windows.h> +#include <io.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#endif +#include "assuan-defs.h" + +/* Hacks for Slowaris. */ +#ifndef PF_LOCAL +# ifdef PF_UNIX +# define PF_LOCAL PF_UNIX +# else +# define PF_LOCAL AF_UNIX +# endif +#endif +#ifndef AF_LOCAL +# define AF_LOCAL AF_UNIX +#endif + +int +_assuan_close (int fd) +{ +#ifndef HAVE_W32_SYSTEM + return close (fd); +#else + int rc = closesocket (fd); + if (rc && WSAGetLastError () == WSAENOTSOCK) + rc = close (fd); + return rc; +#endif +} + + +int +_assuan_sock_new (int domain, int type, int proto) +{ +#ifndef HAVE_W32_SYSTEM + return socket (domain, type, proto); +#else + if (domain == AF_UNIX || domain == AF_LOCAL) + domain = AF_INET; + return socket (domain, type, proto); +#endif +} + + +int +_assuan_sock_connect (int sockfd, struct sockaddr * addr, int addrlen) +{ +#ifndef HAVE_W32_SYSTEM + return connect (sockfd, addr, addrlen); +#else + struct sockaddr_in myaddr; + struct sockaddr_un * unaddr; + FILE * fp; + int port = 0; + + unaddr = (struct sockaddr_un *)addr; + fp = fopen (unaddr->sun_path, "rb"); + if (!fp) + return -1; + fscanf (fp, "%d", &port); + fclose (fp); + /* XXX: set errno in this case */ + if (port < 0 || port > 65535) + return -1; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = port; + myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* we need this later. */ + unaddr->sun_family = myaddr.sin_family; + unaddr->sun_port = myaddr.sin_port; + unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; + + return connect (sockfd, (struct sockaddr *)&myaddr, sizeof myaddr); +#endif +} + + +int +_assuan_sock_bind (int sockfd, struct sockaddr * addr, int addrlen) +{ +#ifndef HAVE_W32_SYSTEM + return bind (sockfd, addr, addrlen); +#else + if (addr->sa_family == AF_LOCAL || addr->sa_family == AF_UNIX) + { + struct sockaddr_in myaddr; + struct sockaddr_un * unaddr; + FILE * fp; + int len = sizeof myaddr; + int rc; + + myaddr.sin_port = 0; + myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + rc = bind (sockfd, (struct sockaddr *)&myaddr, len); + if (rc) + return rc; + rc = getsockname (sockfd, (struct sockaddr *)&myaddr, &len); + if (rc) + return rc; + unaddr = (struct sockaddr_un *)addr; + fp = fopen (unaddr->sun_path, "wb"); + if (!fp) + return -1; + fprintf (fp, "%d", myaddr.sin_port); + fclose (fp); + + /* we need this later. */ + unaddr->sun_family = myaddr.sin_family; + unaddr->sun_port = myaddr.sin_port; + unaddr->sun_addr.s_addr = myaddr.sin_addr.s_addr; + + return 0; + } + return bind (sockfd, addr, addrlen); +#endif +} + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-uds.c b/libkdenetwork/libgpgme-copy/assuan/assuan-uds.c new file mode 100644 index 000000000..77945fb50 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-uds.c @@ -0,0 +1,311 @@ +/* assuan-uds.c - Assuan unix domain socket utilities + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/socket.h> +#include <sys/un.h> +#else +#include <windows.h> +#endif +#if HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <assert.h> + +#include "assuan-defs.h" + +#ifdef USE_DESCRIPTOR_PASSING +/* Provide replacement for missing CMSG maccros. We assume that + size_t matches the alignment requirement. */ +#define MY_ALIGN(n) ((((n))+ sizeof(size_t)-1) & (size_t)~(sizeof(size_t)-1)) +#ifndef CMSG_SPACE +#define CMSG_SPACE(n) (MY_ALIGN(sizeof(struct cmsghdr)) + MY_ALIGN((n))) +#endif +#ifndef CMSG_LEN +#define CMSG_LEN(n) (MY_ALIGN(sizeof(struct cmsghdr)) + (n)) +#endif +#ifndef CMSG_FIRSTHDR +#define CMSG_FIRSTHDR(mhdr) \ + ((size_t)(mhdr)->msg_controllen >= sizeof (struct cmsghdr) \ + ? (struct cmsghdr*) (mhdr)->msg_control : (struct cmsghdr*)NULL) +#endif +#ifndef CMSG_DATA +#define CMSG_DATA(cmsg) ((unsigned char*)((struct cmsghdr*)(cmsg)+1)) +#endif +#endif /*USE_DESCRIPTOR_PASSING*/ + + +/* Read from a unix domain socket using sendmsg. + + FIXME: We don't need the buffering. It is a leftover from the time + when we used datagrams. */ +static ssize_t +uds_reader (assuan_context_t ctx, void *buf, size_t buflen) +{ + int len = ctx->uds.buffersize; + +#ifndef HAVE_W32_SYSTEM + if (!ctx->uds.bufferallocated) + { + ctx->uds.buffer = xtrymalloc (2048); + if (!ctx->uds.buffer) + return _assuan_error (ASSUAN_Out_Of_Core); + ctx->uds.bufferallocated = 2048; + } + + while (!len) /* No data is buffered. */ + { + struct msghdr msg; + struct iovec iovec; +#ifdef USE_DESCRIPTOR_PASSING + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof (int))]; + } control_u; + struct cmsghdr *cmptr; +#endif /*USE_DESCRIPTOR_PASSING*/ + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iovec; + msg.msg_iovlen = 1; + iovec.iov_base = ctx->uds.buffer; + iovec.iov_len = ctx->uds.bufferallocated; +#ifdef USE_DESCRIPTOR_PASSING + msg.msg_control = control_u.control; + msg.msg_controllen = sizeof (control_u.control); +#endif + + len = _assuan_simple_recvmsg (ctx, &msg); + if (len < 0) + return -1; + + ctx->uds.buffersize = len; + ctx->uds.bufferoffset = 0; + +#ifdef USE_DESCRIPTOR_PASSING + cmptr = CMSG_FIRSTHDR (&msg); + if (cmptr && cmptr->cmsg_len == CMSG_LEN (sizeof(int))) + { + if (cmptr->cmsg_level != SOL_SOCKET + || cmptr->cmsg_type != SCM_RIGHTS) + _assuan_log_printf ("unexpected ancillary data received\n"); + else + { + int fd = *((int*)CMSG_DATA (cmptr)); + + if (ctx->uds.pendingfdscount >= DIM (ctx->uds.pendingfds)) + { + _assuan_log_printf ("too many descriptors pending - " + "closing received descriptor %d\n", fd); + _assuan_close (fd); + } + else + ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = fd; + } + } +#endif /*USE_DESCRIPTOR_PASSING*/ + } + +#else /*HAVE_W32_SYSTEM*/ + + len = recvfrom (ctx->inbound.fd, buf, buflen, 0, NULL, NULL); + +#endif /*HAVE_W32_SYSTEM*/ + + /* Return some data to the user. */ + + if (len > buflen) /* We have more than the user requested. */ + len = buflen; + + memcpy (buf, ctx->uds.buffer + ctx->uds.bufferoffset, len); + ctx->uds.buffersize -= len; + assert (ctx->uds.buffersize >= 0); + ctx->uds.bufferoffset += len; + assert (ctx->uds.bufferoffset <= ctx->uds.bufferallocated); + + return len; +} + + +/* Write to the domain server. */ +static ssize_t +uds_writer (assuan_context_t ctx, const void *buf, size_t buflen) +{ +#ifndef HAVE_W32_SYSTEM + struct msghdr msg; + struct iovec iovec; + ssize_t len; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_iov = &iovec; + iovec.iov_base = (void*)buf; + iovec.iov_len = buflen; + + len = _assuan_simple_sendmsg (ctx, &msg); +#else /*HAVE_W32_SYSTEM*/ + int len; + + len = sendto (ctx->outbound.fd, buf, buflen, 0, + (struct sockaddr *)&ctx->serveraddr, + sizeof (struct sockaddr_in)); +#endif /*HAVE_W32_SYSTEM*/ + return len; +} + + +static assuan_error_t +uds_sendfd (assuan_context_t ctx, int fd) +{ +#ifdef USE_DESCRIPTOR_PASSING + struct msghdr msg; + struct iovec iovec; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof (int))]; + } control_u; + struct cmsghdr *cmptr; + int len; + char buffer[80]; + + /* We need to send some real data so that a read won't return 0 + which will be taken as an EOF. It also helps with debugging. */ + snprintf (buffer, sizeof(buffer)-1, "# descriptor %d is in flight\n", fd); + buffer[sizeof(buffer)-1] = 0; + + memset (&msg, 0, sizeof (msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iovlen = 1; + msg.msg_iov = &iovec; + iovec.iov_base = buffer; + iovec.iov_len = strlen (buffer); + + msg.msg_control = control_u.control; + msg.msg_controllen = sizeof (control_u.control); + cmptr = CMSG_FIRSTHDR (&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(int)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + *((int*)CMSG_DATA (cmptr)) = fd; + + len = _assuan_simple_sendmsg (ctx, &msg); + if (len < 0) + { + _assuan_log_printf ("uds_sendfd: %s\n", strerror (errno)); + return _assuan_error (ASSUAN_Write_Error); + } + else + return 0; +#else + return _assuan_error (ASSUAN_Not_Implemented); +#endif +} + + +static assuan_error_t +uds_receivefd (assuan_context_t ctx, int *fd) +{ +#ifdef USE_DESCRIPTOR_PASSING + int i; + + if (!ctx->uds.pendingfdscount) + { + _assuan_log_printf ("no pending file descriptors!\n"); + return _assuan_error (ASSUAN_General_Error); + } + assert (ctx->uds.pendingfdscount <= DIM(ctx->uds.pendingfds)); + + *fd = ctx->uds.pendingfds[0]; + for (i=1; i < ctx->uds.pendingfdscount; i++) + ctx->uds.pendingfds[i-1] = ctx->uds.pendingfds[i]; + ctx->uds.pendingfdscount--; + + return 0; +#else + return _assuan_error (ASSUAN_Not_Implemented); +#endif +} + + +/* Close all pending fds. */ +void +_assuan_uds_close_fds (assuan_context_t ctx) +{ + int i; + + for (i = 0; i < ctx->uds.pendingfdscount; i++) + _assuan_close (ctx->uds.pendingfds[i]); + ctx->uds.pendingfdscount = 0; +} + +/* Deinitialize the unix domain socket I/O functions. */ +void +_assuan_uds_deinit (assuan_context_t ctx) +{ + /* First call the finish_handler which should close descriptors etc. */ + ctx->finish_handler (ctx); + + if (ctx->uds.buffer) + { + assert (ctx->uds.bufferallocated); + ctx->uds.bufferallocated = 0; + xfree (ctx->uds.buffer); + } + + _assuan_uds_close_fds (ctx); +} + + +/* Helper function to initialize a context for domain I/O. */ +void +_assuan_init_uds_io (assuan_context_t ctx) +{ + static struct assuan_io io = { uds_reader, uds_writer, + uds_sendfd, uds_receivefd }; + + ctx->io = &io; + ctx->uds.buffer = 0; + ctx->uds.bufferoffset = 0; + ctx->uds.buffersize = 0; + ctx->uds.bufferallocated = 0; + ctx->uds.pendingfdscount = 0; +} + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan-util.c b/libkdenetwork/libgpgme-copy/assuan/assuan-util.c new file mode 100644 index 000000000..d12277fcc --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan-util.c @@ -0,0 +1,171 @@ +/* assuan-util.c - Utility functions for Assuan + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "assuan-defs.h" + +static void *(*alloc_func)(size_t n) = malloc; +static void *(*realloc_func)(void *p, size_t n) = realloc; +static void (*free_func)(void*) = free; + +void +assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), + void *(*new_realloc_func)(void *p, size_t n), + void (*new_free_func)(void*) ) +{ + alloc_func = new_alloc_func; + realloc_func = new_realloc_func; + free_func = new_free_func; +} + +void * +_assuan_malloc (size_t n) +{ + return alloc_func (n); +} + +void * +_assuan_realloc (void *a, size_t n) +{ + return realloc_func (a, n); +} + +void * +_assuan_calloc (size_t n, size_t m) +{ + void *p; + size_t nbytes; + + nbytes = n * m; + if (m && nbytes / m != n) + { + errno = ENOMEM; + return NULL; + } + + p = _assuan_malloc (nbytes); + if (p) + memset (p, 0, nbytes); + return p; +} + +void +_assuan_free (void *p) +{ + if (p) + free_func (p); +} + + +/* Store the error in the context so that the error sending function + can take out a descriptive text. Inside the assuan code, use the + macro set_error instead of this function. */ +int +assuan_set_error (assuan_context_t ctx, int err, const char *text) +{ + ctx->err_no = err; + ctx->err_str = text; + return err; +} + +void +assuan_set_pointer (assuan_context_t ctx, void *pointer) +{ + if (ctx) + ctx->user_pointer = pointer; +} + +void * +assuan_get_pointer (assuan_context_t ctx) +{ + return ctx? ctx->user_pointer : NULL; +} + + +void +assuan_begin_confidential (assuan_context_t ctx) +{ + if (ctx) + { + ctx->confidential = 1; + } +} + +void +assuan_end_confidential (assuan_context_t ctx) +{ + if (ctx) + { + ctx->confidential = 0; + } +} + + +void +assuan_set_io_monitor (assuan_context_t ctx, + unsigned int (*monitor)(assuan_context_t ctx, + int direction, + const char *line, + size_t linelen)) +{ + if (ctx) + { + ctx->io_monitor = monitor; + } +} + + + + +/* For context CTX, set the flag FLAG to VALUE. Values for flags + are usually 1 or 0 but certain flags might allow for other values; + see the description of the type assuan_flag_t for details. */ +void +assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value) +{ + if (!ctx) + return; + switch (flag) + { + case ASSUAN_NO_WAITPID: ctx->flags.no_waitpid = value; break; + } +} + +/* Return the VALUE of FLAG in context CTX. */ +int +assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag) +{ + if (!ctx) + return 0; + switch (flag) + { + case ASSUAN_NO_WAITPID: return ctx->flags.no_waitpid; + } + return 0; +} + + diff --git a/libkdenetwork/libgpgme-copy/assuan/assuan.h b/libkdenetwork/libgpgme-copy/assuan/assuan.h new file mode 100644 index 000000000..cdf0445ab --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/assuan.h @@ -0,0 +1,565 @@ +/* assuan.c - Definitions for the Assuan IPC library + * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifndef ASSUAN_H +#define ASSUAN_H + +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> + + +/* To use this file with libraries the following macros are useful: + + #define _ASSUAN_EXT_SYM_PREFIX _foo_ + + This prefixes all external symbols with "_foo_". + + #define _ASSUAN_ONLY_GPG_ERRORS + + If this is defined all old-style Assuan error codes are made + inactive as well as other dereacted stuff. + + The follwing macros are used internally in the implementation of + libassuan: + + #define _ASSUAN_NO_PTH + + This avoids inclusion of special GNU Pth hacks. + + #define _ASSUAN_NO_FIXED_SIGNALS + + This disables changing of certain signal handler; i.e. SIGPIPE. + + #define _ASSUAN_USE_DOUBLE_FORK + + Use a double fork approach when connecting to a server through + a pipe. + */ +/**** Begin GPGME specific modifications. ******/ +#define _ASSUAN_EXT_SYM_PREFIX _gpgme_ +#define _ASSUAN_NO_PTH +#define _ASSUAN_NO_FIXED_SIGNALS +#define _ASSUAN_USE_DOUBLE_FORK + +#ifdef _ASSUAN_IN_GPGME_BUILD_ASSUAN +int _gpgme_io_read (int fd, void *buffer, size_t count); +int _gpgme_io_write (int fd, const void *buffer, size_t count); +ssize_t _gpgme_ath_waitpid (pid_t pid, int *status, int options); +#ifdef HAVE_W32_SYSTEM +int _gpgme_ath_accept (int s, void *addr, int *length_ptr); +#else /*!HAVE_W32_SYSTEM*/ +struct sockaddr; +struct msghdr; +ssize_t _gpgme_ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout); +int _gpgme_ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr); +int _gpgme_ath_connect (int s, struct sockaddr *addr, socklen_t length); +int _gpgme_ath_sendmsg (int s, const struct msghdr *msg, int flags); +int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); +int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags); +int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); +#endif /*!HAVE_W32_SYSTEM*/ + +#define read _gpgme_io_read +#define write _gpgme_io_write +#define waitpid _gpgme_ath_waitpid +#define select _gpgme_ath_select +#define accept _gpgme_ath_accept +#define connect _gpgme_ath_connect +#define sendmsg _gpgme_io_sendmsg +#define recvmsg _gpgme_io_recvmsg +#endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/ +/**** End GPGME specific modifications. ******/ + + +#ifdef _ASSUAN_EXT_SYM_PREFIX +#define _ASSUAN_PREFIX1(x,y) x ## y +#define _ASSUAN_PREFIX2(x,y) _ASSUAN_PREFIX1(x,y) +#define _ASSUAN_PREFIX(x) _ASSUAN_PREFIX2(_ASSUAN_EXT_SYM_PREFIX,x) +#define assuan_ _ASSUAN_PREFIX(assuan_) +#define assuan_register_command _ASSUAN_PREFIX(assuan_register_command) +#define assuan_register_post_cmd_notify \ + _ASSUAN_PREFIX(assuan_register_post_cmd_notify) +#define assuan_register_bye_notify _ASSUAN_PREFIX(assuan_register_bye_notify) +#define assuan_register_reset_notify \ + _ASSUAN_PREFIX(assuan_register_reset_notify) +#define assuan_register_cancel_notify \ + _ASSUAN_PREFIX(assuan_register_cancel_notify) +#define assuan_register_input_notify \ + _ASSUAN_PREFIX(assuan_register_input_notify) +#define assuan_register_output_notify \ + _ASSUAN_PREFIX(assuan_register_output_notify) +#define assuan_register_option_handler \ + _ASSUAN_PREFIX(assuan_register_option_handler) +#define assuan_process _ASSUAN_PREFIX(assuan_process) +#define assuan_process_next _ASSUAN_PREFIX(assuan_process_next) +#define assuan_get_active_fds _ASSUAN_PREFIX(assuan_get_active_fds) +#define assuan_get_data_fp _ASSUAN_PREFIX(assuan_get_data_fp) +#define assuan_set_okay_line _ASSUAN_PREFIX(assuan_set_okay_line) +#define assuan_write_status _ASSUAN_PREFIX(assuan_write_status) +#define assuan_command_parse_fd _ASSUAN_PREFIX(assuan_command_parse_fd) +#define assuan_set_hello_line _ASSUAN_PREFIX(assuan_set_hello_line) +#define assuan_accept _ASSUAN_PREFIX(assuan_accept) +#define assuan_get_input_fd _ASSUAN_PREFIX(assuan_get_input_fd) +#define assuan_get_output_fd _ASSUAN_PREFIX(assuan_get_output_fd) +#define assuan_close_input_fd _ASSUAN_PREFIX(assuan_close_input_fd) +#define assuan_close_output_fd _ASSUAN_PREFIX(assuan_close_output_fd) +#define assuan_init_pipe_server _ASSUAN_PREFIX(assuan_init_pipe_server) +#define assuan_deinit_server _ASSUAN_PREFIX(assuan_deinit_server) +#define assuan_init_socket_server _ASSUAN_PREFIX(assuan_init_socket_server) +#define assuan_init_connected_socket_server \ + _ASSUAN_PREFIX(assuan_init_connected_socket_server) +#define assuan_init_socket_server_ext \ + _ASSUAN_PREFIX(assuan_init_socket_server_ext) +#define assuan_pipe_connect _ASSUAN_PREFIX(assuan_pipe_connect) +#define assuan_pipe_connect_ext _ASSUAN_PREFIX(assuan_pipe_connect_ext) +#define assuan_socket_connect _ASSUAN_PREFIX(assuan_socket_connect) +#define assuan_socket_connect_ext _ASSUAN_PREFIX(assuan_socket_connect_ext) +#define assuan_disconnect _ASSUAN_PREFIX(assuan_disconnect) +#define assuan_get_pid _ASSUAN_PREFIX(assuan_get_pid) +#define assuan_get_peercred _ASSUAN_PREFIX(assuan_get_peercred) +#define assuan_transact _ASSUAN_PREFIX(assuan_transact) +#define assuan_inquire _ASSUAN_PREFIX(assuan_inquire) +#define assuan_read_line _ASSUAN_PREFIX(assuan_read_line) +#define assuan_pending_line _ASSUAN_PREFIX(assuan_pending_line) +#define assuan_write_line _ASSUAN_PREFIX(assuan_write_line) +#define assuan_send_data _ASSUAN_PREFIX(assuan_send_data) +#define assuan_sendfd _ASSUAN_PREFIX(assuan_sendfd) +#define assuan_receivefd _ASSUAN_PREFIX(assuan_receivefd) +#define assuan_set_malloc_hooks _ASSUAN_PREFIX(assuan_set_malloc_hooks) +#define assuan_set_log_stream _ASSUAN_PREFIX(assuan_set_log_stream) +#define assuan_set_error _ASSUAN_PREFIX(assuan_set_error) +#define assuan_set_pointer _ASSUAN_PREFIX(assuan_set_pointer) +#define assuan_get_pointer _ASSUAN_PREFIX(assuan_get_pointer) +#define assuan_set_io_monitor _ASSUAN_PREFIX(assuan_set_io_monitor) +#define assuan_begin_confidential _ASSUAN_PREFIX(assuan_begin_confidential) +#define assuan_end_confidential _ASSUAN_PREFIX(assuan_end_confidential) +#define assuan_strerror _ASSUAN_PREFIX(assuan_strerror) +#define assuan_set_assuan_err_source \ + _ASSUAN_PREFIX(assuan_set_assuan_err_source) +#define assuan_set_assuan_log_stream \ + _ASSUAN_PREFIX(assuan_set_assuan_log_stream) +#define assuan_get_assuan_log_stream \ + _ASSUAN_PREFIX(assuan_get_assuan_log_stream) +#define assuan_get_assuan_log_prefix \ + _ASSUAN_PREFIX(assuan_get_assuan_log_prefix) +#define assuan_set_flag _ASSUAN_PREFIX(assuan_set_flag) +#define assuan_get_flag _ASSUAN_PREFIX(assuan_get_flag) + +/* And now the internal functions, argh... */ +#define _assuan_read_line _ASSUAN_PREFIX(_assuan_read_line) +#define _assuan_cookie_write_data _ASSUAN_PREFIX(_assuan_cookie_write_data) +#define _assuan_cookie_write_flush _ASSUAN_PREFIX(_assuan_cookie_write_flush) +#define _assuan_read_from_server _ASSUAN_PREFIX(_assuan_read_from_server) +#define _assuan_domain_init _ASSUAN_PREFIX(_assuan_domain_init) +#define _assuan_register_std_commands \ + _ASSUAN_PREFIX(_assuan_register_std_commands) +#define _assuan_simple_read _ASSUAN_PREFIX(_assuan_simple_read) +#define _assuan_simple_write _ASSUAN_PREFIX(_assuan_simple_write) +#define _assuan_simple_read _ASSUAN_PREFIX(_assuan_simple_read) +#define _assuan_simple_write _ASSUAN_PREFIX(_assuan_simple_write) +#define _assuan_new_context _ASSUAN_PREFIX(_assuan_new_context) +#define _assuan_release_context _ASSUAN_PREFIX(_assuan_release_context) +#define _assuan_malloc _ASSUAN_PREFIX(_assuan_malloc) +#define _assuan_realloc _ASSUAN_PREFIX(_assuan_realloc) +#define _assuan_calloc _ASSUAN_PREFIX(_assuan_calloc) +#define _assuan_free _ASSUAN_PREFIX(_assuan_free) +#define _assuan_log_print_buffer _ASSUAN_PREFIX(_assuan_log_print_buffer) +#define _assuan_log_sanitized_string \ + _ASSUAN_PREFIX(_assuan_log_sanitized_string) +#define _assuan_log_printf _ASSUAN_PREFIX(_assuan_log_printf) +#define _assuan_set_default_log_stream \ + _ASSUAN_PREFIX(_assuan_set_default_log_stream) +#define _assuan_w32_strerror _ASSUAN_PREFIX(_assuan_w32_strerror) +#define _assuan_write_line _ASSUAN_PREFIX(_assuan_write_line) +#define _assuan_close _ASSUAN_PREFIX(_assuan_close) +#define _assuan_sock_new _ASSUAN_PREFIX(_assuan_sock_new) +#define _assuan_sock_bind _ASSUAN_PREFIX(_assuan_sock_bind) +#define _assuan_sock_connect _ASSUAN_PREFIX(_assuan_sock_connect) + +#endif /*_ASSUAN_EXT_SYM_PREFIX*/ + + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} +#endif +#endif + + +/* Check for compiler features. */ +#if __GNUC__ +#define _ASSUAN_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +#if _ASSUAN_GCC_VERSION > 30100 +#define _ASSUAN_DEPRECATED __attribute__ ((__deprecated__)) +#endif +#endif +#ifndef _ASSUAN_DEPRECATED +#define _ASSUAN_DEPRECATED +#endif + + +/* Assuan error codes. These are only used by old applications or + those applications which won't make use of libgpg-error. */ +#ifndef _ASSUAN_ONLY_GPG_ERRORS +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_No_Error 0 +#endif +#define ASSUAN_General_Error 1 +#define ASSUAN_Out_Of_Core 2 +#define ASSUAN_Invalid_Value 3 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Timeout 4 +#endif +#define ASSUAN_Read_Error 5 +#define ASSUAN_Write_Error 6 +#define ASSUAN_Problem_Starting_Server 7 +#define ASSUAN_Not_A_Server 8 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Not_A_Client 9 +#endif +#define ASSUAN_Nested_Commands 10 +#define ASSUAN_Invalid_Response 11 +#define ASSUAN_No_Data_Callback 12 +#define ASSUAN_No_Inquire_Callback 13 +#define ASSUAN_Connect_Failed 14 +#define ASSUAN_Accept_Failed 15 + + /* Error codes above 99 are meant as status codes */ +#define ASSUAN_Not_Implemented 100 +#define ASSUAN_Server_Fault 101 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Invalid_Command 102 +#endif +#define ASSUAN_Unknown_Command 103 +#define ASSUAN_Syntax_Error 104 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Parameter_Error 105 +#endif +#define ASSUAN_Parameter_Conflict 106 +#define ASSUAN_Line_Too_Long 107 +#define ASSUAN_Line_Not_Terminated 108 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_No_Input 109 +#define ASSUAN_No_Output 110 +#endif +#define ASSUAN_Canceled 111 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Unsupported_Algorithm 112 +#define ASSUAN_Server_Resource_Problem 113 +#define ASSUAN_Server_IO_Error 114 +#define ASSUAN_Server_Bug 115 +#define ASSUAN_No_Data_Available 116 +#define ASSUAN_Invalid_Data 117 +#endif +#define ASSUAN_Unexpected_Command 118 +#define ASSUAN_Too_Much_Data 119 +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Inquire_Unknown 120 +#define ASSUAN_Inquire_Error 121 +#define ASSUAN_Invalid_Option 122 +#define ASSUAN_Invalid_Index 123 +#define ASSUAN_Unexpected_Status 124 +#define ASSUAN_Unexpected_Data 125 +#define ASSUAN_Invalid_Status 126 +#define ASSUAN_Locale_Problem 127 +#endif +#define ASSUAN_Not_Confirmed 128 + + /* Warning: Don't use the Error codes, below they are deprecated. */ +#ifndef _ASSUAN_IN_LIBASSUAN +#define ASSUAN_Bad_Certificate 201 +#define ASSUAN_Bad_Certificate_Chain 202 +#define ASSUAN_Missing_Certificate 203 +#define ASSUAN_Bad_Signature 204 +#define ASSUAN_No_Agent 205 +#define ASSUAN_Agent_Error 206 +#define ASSUAN_No_Public_Key 207 +#define ASSUAN_No_Secret_Key 208 +#define ASSUAN_Invalid_Name 209 + +#define ASSUAN_Cert_Revoked 301 +#define ASSUAN_No_CRL_For_Cert 302 +#define ASSUAN_CRL_Too_Old 303 +#define ASSUAN_Not_Trusted 304 + +#define ASSUAN_Card_Error 401 +#define ASSUAN_Invalid_Card 402 +#define ASSUAN_No_PKCS15_App 403 +#define ASSUAN_Card_Not_Present 404 +#define ASSUAN_Invalid_Id 405 + + /* Error codes in the range 1000 to 9999 may be used by applications + at their own discretion. */ +#define ASSUAN_USER_ERROR_FIRST 1000 +#define ASSUAN_USER_ERROR_LAST 9999 +#endif + +typedef int assuan_error_t; + +typedef assuan_error_t AssuanError _ASSUAN_DEPRECATED; + +/* This is a list of pre-registered ASSUAN commands */ +/* Note, these command IDs are now deprectated and solely exists for + compatibility reasons. */ +typedef enum +{ + ASSUAN_CMD_NOP = 0, + ASSUAN_CMD_CANCEL, /* cancel the current request */ + ASSUAN_CMD_BYE, + ASSUAN_CMD_AUTH, + ASSUAN_CMD_RESET, + ASSUAN_CMD_OPTION, + ASSUAN_CMD_DATA, + ASSUAN_CMD_END, + ASSUAN_CMD_INPUT, + ASSUAN_CMD_OUTPUT, + + ASSUAN_CMD_USER = 256 /* Other commands should be used with this offset*/ +} AssuanCommand; + + +#else /*!_ASSUAN_ONLY_GPG_ERRORS*/ + +typedef int assuan_error_t; + +#endif /*!_ASSUAN_ONLY_GPG_ERRORS*/ + + +/* Definitions of flags for assuan_set_flag(). */ +typedef enum + { + /* When using a pipe server, by default Assuan will wait for the + forked process to die in assuan_disconnect. In certain cases + this is not desirable. By setting this flag, the waitpid will + be skipped and the caller is responsible to cleanup a forked + process. */ + ASSUAN_NO_WAITPID = 1 + } +assuan_flag_t; + +#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */ + +struct assuan_context_s; +typedef struct assuan_context_s *assuan_context_t; +#ifndef _ASSUAN_ONLY_GPG_ERRORS +typedef struct assuan_context_s *ASSUAN_CONTEXT _ASSUAN_DEPRECATED; +#endif /*_ASSUAN_ONLY_GPG_ERRORS*/ + +/*-- assuan-handler.c --*/ +int assuan_register_command (assuan_context_t ctx, + const char *cmd_string, + int (*handler)(assuan_context_t, char *)); +int assuan_register_post_cmd_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, int)); +int assuan_register_bye_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)); +int assuan_register_reset_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)); +int assuan_register_cancel_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t)); +int assuan_register_input_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)); +int assuan_register_output_notify (assuan_context_t ctx, + void (*fnc)(assuan_context_t, const char *)); + +int assuan_register_option_handler (assuan_context_t ctx, + int (*fnc)(assuan_context_t, + const char*, const char*)); + +int assuan_process (assuan_context_t ctx); +int assuan_process_next (assuan_context_t ctx); +int assuan_get_active_fds (assuan_context_t ctx, int what, + int *fdarray, int fdarraysize); + + +FILE *assuan_get_data_fp (assuan_context_t ctx); +assuan_error_t assuan_set_okay_line (assuan_context_t ctx, const char *line); +assuan_error_t assuan_write_status (assuan_context_t ctx, + const char *keyword, const char *text); + +/* Negotiate a file descriptor. If LINE contains "FD=N", returns N + assuming a local file descriptor. If LINE contains "FD" reads a + file descriptor via CTX and stores it in *RDF (the CTX must be + capable of passing file descriptors). */ +assuan_error_t assuan_command_parse_fd (assuan_context_t ctx, char *line, + int *rfd); + +/*-- assuan-listen.c --*/ +assuan_error_t assuan_set_hello_line (assuan_context_t ctx, const char *line); +assuan_error_t assuan_accept (assuan_context_t ctx); +int assuan_get_input_fd (assuan_context_t ctx); +int assuan_get_output_fd (assuan_context_t ctx); +assuan_error_t assuan_close_input_fd (assuan_context_t ctx); +assuan_error_t assuan_close_output_fd (assuan_context_t ctx); + + +/*-- assuan-pipe-server.c --*/ +int assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2]); +void assuan_deinit_server (assuan_context_t ctx); + +/*-- assuan-socket-server.c --*/ +int assuan_init_socket_server (assuan_context_t *r_ctx, int listen_fd); +int assuan_init_connected_socket_server (assuan_context_t *r_ctx, + int fd) _ASSUAN_DEPRECATED; +int assuan_init_socket_server_ext (assuan_context_t *r_ctx, int fd, + unsigned int flags); + +/*-- assuan-pipe-connect.c --*/ +assuan_error_t assuan_pipe_connect (assuan_context_t *ctx, + const char *name, + const char *const argv[], + int *fd_child_list); +assuan_error_t assuan_pipe_connect2 (assuan_context_t *ctx, + const char *name, + const char *const argv[], + int *fd_child_list, + void (*atfork) (void*, int), + void *atforkvalue) _ASSUAN_DEPRECATED; +assuan_error_t assuan_pipe_connect_ext (assuan_context_t *ctx, + const char *name, + const char *const argv[], + int *fd_child_list, + void (*atfork) (void *, int), + void *atforkvalue, + unsigned int flags); + +/*-- assuan-socket-connect.c --*/ +assuan_error_t assuan_socket_connect (assuan_context_t *ctx, + const char *name, + pid_t server_pid); +assuan_error_t assuan_socket_connect_ext (assuan_context_t *ctx, + const char *name, + pid_t server_pid, + unsigned int flags); + +/*-- assuan-connect.c --*/ +void assuan_disconnect (assuan_context_t ctx); +pid_t assuan_get_pid (assuan_context_t ctx); +assuan_error_t assuan_get_peercred (assuan_context_t ctx, + pid_t *pid, uid_t *uid, gid_t *gid); + +/*-- assuan-client.c --*/ +assuan_error_t +assuan_transact (assuan_context_t ctx, + const char *command, + int (*data_cb)(void *, const void *, size_t), + void *data_cb_arg, + int (*inquire_cb)(void*, const char *), + void *inquire_cb_arg, + int (*status_cb)(void*, const char *), + void *status_cb_arg); + + +/*-- assuan-inquire.c --*/ +assuan_error_t assuan_inquire (assuan_context_t ctx, const char *keyword, + unsigned char **r_buffer, size_t *r_length, + size_t maxlen); + +/*-- assuan-buffer.c --*/ +assuan_error_t assuan_read_line (assuan_context_t ctx, + char **line, size_t *linelen); +int assuan_pending_line (assuan_context_t ctx); +assuan_error_t assuan_write_line (assuan_context_t ctx, const char *line ); +assuan_error_t assuan_send_data (assuan_context_t ctx, + const void *buffer, size_t length); + +/* The file descriptor must be pending before assuan_receivefd is + called. This means that assuan_sendfd should be called *before* the + trigger is sent (normally via assuan_write_line ("INPUT FD")). */ +assuan_error_t assuan_sendfd (assuan_context_t ctx, int fd); +assuan_error_t assuan_receivefd (assuan_context_t ctx, int *fd); + +/*-- assuan-util.c --*/ +void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n), + void *(*new_realloc_func)(void *p, size_t n), + void (*new_free_func)(void*) ); +void assuan_set_log_stream (assuan_context_t ctx, FILE *fp); +int assuan_set_error (assuan_context_t ctx, int err, const char *text); +void assuan_set_pointer (assuan_context_t ctx, void *pointer); +void *assuan_get_pointer (assuan_context_t ctx); + +void assuan_begin_confidential (assuan_context_t ctx); +void assuan_end_confidential (assuan_context_t ctx); + +void assuan_set_io_monitor (assuan_context_t ctx, + unsigned int (*monitor)(assuan_context_t ctx, + int direction, + const char *line, + size_t linelen)); + +/* For context CTX, set the flag FLAG to VALUE. Values for flags + are usually 1 or 0 but certain flags might allow for other values; + see the description of the type assuan_flag_t for details. */ +void assuan_set_flag (assuan_context_t ctx, assuan_flag_t flag, int value); + +/* Return the VALUE of FLAG in context CTX. */ +int assuan_get_flag (assuan_context_t ctx, assuan_flag_t flag); + + +/*-- assuan-errors.c --*/ + +#ifndef _ASSUAN_ONLY_GPG_ERRORS +/* Return a string describing the assuan error. The use of this + function is deprecated; it is better to call + assuan_set_assuan_err_source once and then make use libgpg-error. */ +const char *assuan_strerror (assuan_error_t err); +#endif /*_ASSUAN_ONLY_GPG_ERRORS*/ + +/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error + sources. Note, that this function is not thread-safe and should be + used right at startup. Switching back to the old style mode is not + supported. */ +void assuan_set_assuan_err_source (int errsource); + +/*-- assuan-logging.c --*/ + +/* Set the stream to which assuan should log message not associated + with a context. By default, this is stderr. The default value + will be changed when the first log stream is associated with a + context. Note, that this function is not thread-safe and should + in general be used right at startup. */ +extern void assuan_set_assuan_log_stream (FILE *fp); + +/* Return the stream which is currently being using for global logging. */ +extern FILE *assuan_get_assuan_log_stream (void); + +/* Set the prefix to be used at the start of a line emitted by assuan + on the log stream. The default is the empty string. Note, that + this function is not thread-safe and should in general be used + right at startup. */ +void assuan_set_assuan_log_prefix (const char *text); + +/* Return a prefix to be used at the start of a line emitted by assuan + on the log stream. The default implementation returns the empty + string, i.e. "" */ +const char *assuan_get_assuan_log_prefix (void); + +#ifdef __cplusplus +} +#endif +#endif /* ASSUAN_H */ diff --git a/libkdenetwork/libgpgme-copy/assuan/funopen.c b/libkdenetwork/libgpgme-copy/assuan/funopen.c new file mode 100644 index 000000000..ac31007a6 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/funopen.c @@ -0,0 +1,64 @@ +/* funopen.c - Replacement for funopen. + * Copyright (C) 2003, 2005 Free Software Foundation, Inc. + * + * This file is part of Assuan. + * + * Assuan 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. + * + * Assuan 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> + + +/* Replacement for the *BSD function: + + FILE *funopen (void *cookie, + int (*readfn)(void *, char *, int), + int (*writefn)(void *, const char *, int), + fpos_t (*seekfn)(void *, fpos_t, int), + int (*closefn)(void *)); + + The functions to provide my either be NULL if not required or + similar to the unistd function with the exception of using the + cookie instead of the fiel descripor. +*/ + + +#ifdef HAVE_FOPENCOOKIE +FILE * +_assuan_funopen(void *cookie, + cookie_read_function_t *readfn, + cookie_write_function_t *writefn, + cookie_seek_function_t *seekfn, + cookie_close_function_t *closefn) +{ + cookie_io_functions_t io = { NULL }; + + io.read = readfn; + io.write = writefn; + io.seek = seekfn; + io.close = closefn; + + return fopencookie (cookie, + readfn ? ( writefn ? "rw" : "r" ) + : ( writefn ? "w" : ""), io); +} +#else +#error No known way to implement funopen. +#endif diff --git a/libkdenetwork/libgpgme-copy/assuan/mkerrors b/libkdenetwork/libgpgme-copy/assuan/mkerrors new file mode 100755 index 000000000..57485411a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/assuan/mkerrors @@ -0,0 +1,228 @@ +#!/bin/sh +# mkerrors - Extract error strings from assuan.h +# and create C source for assuan_strerror +# Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. +# +# This file is part of Assuan. +# +# Assuan 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. +# +# Assuan 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 + +cat <<EOF +/* Generated automatically by mkerrors */ +/* Do not edit! See mkerrors for copyright notice. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <assert.h> +#include <errno.h> + +#undef _ASSUAN_IN_LIBASSUAN /* undef to get all error codes. */ +#include "assuan.h" + +/* If true the modern gpg-error style error codes are used in the + API. */ +static unsigned int err_source; + +/* Enable gpg-error style error codes. ERRSOURCE is one of gpg-error + sources. Note, that this function is not thread-safe and should be + used right at startup. Switching back to the old style mode is not + supported. */ +void +assuan_set_assuan_err_source (int errsource) +{ + errsource &= 0xff; + err_source = errsource? errsource : 31 /*GPG_ERR_SOURCE_ANY*/; +} + + +/* Helper to map old style Assuan error codes to gpg-error codes. + This is used internally to keep an compatible ABI. */ +assuan_error_t +_assuan_error (int oldcode) +{ + unsigned int n; + + if (!err_source) + return (oldcode & 0x00ffffff); /* Make sure that the gpg-error + source part is cleared. */ + + switch (oldcode) + { + case ASSUAN_General_Error: n = 257; break; + case ASSUAN_Accept_Failed: n = 258; break; + case ASSUAN_Connect_Failed: n = 259; break; + case ASSUAN_Invalid_Response: n = 260; break; + case ASSUAN_Invalid_Value: n = 261; break; + case ASSUAN_Line_Not_Terminated: n = 262; break; + case ASSUAN_Line_Too_Long: n = 263; break; + case ASSUAN_Nested_Commands: n = 264; break; + case ASSUAN_No_Data_Callback: n = 265; break; + case ASSUAN_No_Inquire_Callback: n = 266; break; + case ASSUAN_Not_A_Server: n = 267; break; + case ASSUAN_Not_Implemented: n = 69; break; + case ASSUAN_Parameter_Conflict: n = 280; break; + case ASSUAN_Problem_Starting_Server: n = 269; break; + case ASSUAN_Server_Fault: n = 80; break; + case ASSUAN_Syntax_Error: n = 276; break; + case ASSUAN_Too_Much_Data: n = 273; break; + case ASSUAN_Unexpected_Command: n = 274; break; + case ASSUAN_Unknown_Command: n = 275; break; + case ASSUAN_Canceled: n = 277; break; + case ASSUAN_No_Secret_Key: n = 17; break; + case ASSUAN_Not_Confirmed: n = 114; break; + + case ASSUAN_Read_Error: + switch (errno) + { + case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; + default: n = 270; /*GPG_ERR_ASS_READ_ERROR*/ break; + } + break; + + case ASSUAN_Write_Error: + switch (errno) + { + case 0: n = 16381; /*GPG_ERR_MISSING_ERRNO*/ break; + default: n = 271; /*GPG_ERR_ASS_WRITE_ERROR*/ break; + } + break; + + case ASSUAN_Out_Of_Core: + switch (errno) + { + case 0: /* Should not happen but a user might have provided + an incomplete implemented malloc function. Give + him a chance to correct this fault but make sure + an error is indeed returned. */ + n = 16381; /*GPG_ERR_MISSING_ERRNO*/ + break; + case ENOMEM: n = (1 << 15) | 86; break; + default: + n = 16382; /*GPG_ERR_UNKNOWN_ERRNO*/ + break; + } + break; + + case -1: n = 16383 /*GPG_ERR_EOF*/; break; + + default: + n = 257; + break; + } + + return ((err_source << 24) | (n & 0x00ffffff)); + +} + + +/** + * assuan_strerror: + * @err: Error code + * + * This function returns a textual representaion of the given + * errorcode. If this is an unknown value, a string with the value + * is returned (Beware: it is hold in a static buffer). + * + * Return value: String with the error description. + **/ +const char * +assuan_strerror (assuan_error_t err) +{ + const char *s; + static char buf[50]; + + switch (err) + { +EOF + +awk ' +/ASSUAN_No_Error/ { okay=1 } +!okay {next} +/^#define[ ]+ASSUAN_[A-Za-z_]*/ { print_code($2) } +/ASSUAN_USER_ERROR_LAST/ { exit 0 } + + +function print_code( s ) +{ +printf " case %s: s=\"", s ; +gsub(/_/, " ", s ); +printf "%s\"; break;\n", tolower(substr(s,8)); +} +' + +cat <<EOF + case -1: s = "EOF (-1)"; break; + default: + { + unsigned int source, code, n; + + source = ((err >> 24) & 0xff); + code = (err & 0x00ffffff); + if (source) + { + /* Assume this is an libgpg-error and try to map the codes + back. */ + switch (code) + { + case 257: n = ASSUAN_General_Error ; break; + case 258: n = ASSUAN_Accept_Failed ; break; + case 259: n = ASSUAN_Connect_Failed ; break; + case 260: n = ASSUAN_Invalid_Response ; break; + case 261: n = ASSUAN_Invalid_Value ; break; + case 262: n = ASSUAN_Line_Not_Terminated ; break; + case 263: n = ASSUAN_Line_Too_Long ; break; + case 264: n = ASSUAN_Nested_Commands ; break; + case 265: n = ASSUAN_No_Data_Callback ; break; + case 266: n = ASSUAN_No_Inquire_Callback ; break; + case 267: n = ASSUAN_Not_A_Server ; break; + case 69: n = ASSUAN_Not_Implemented ; break; + case 280: n = ASSUAN_Parameter_Conflict ; break; + case 269: n = ASSUAN_Problem_Starting_Server; break; + case 270: n = ASSUAN_Read_Error ; break; + case 271: n = ASSUAN_Write_Error ; break; + case 80: n = ASSUAN_Server_Fault ; break; + case 276: n = ASSUAN_Syntax_Error ; break; + case 273: n = ASSUAN_Too_Much_Data ; break; + case 274: n = ASSUAN_Unexpected_Command ; break; + case 275: n = ASSUAN_Unknown_Command ; break; + case 277: n = ASSUAN_Canceled ; break; + case 114: n = ASSUAN_Not_Confirmed ; break; + case ((1<<15)|86): n = ASSUAN_Out_Of_Core ; break; + default: n = 0; break; + } + if (n) + s = assuan_strerror (n); + else + { + sprintf (buf, "ec=%u.%u", source, code ); + s=buf; + } + } + else + { + sprintf (buf, "ec=%d", err ); + s=buf; + } + } + break; + } + + return s; +} + +EOF diff --git a/libkdenetwork/libgpgme-copy/configure.in.in b/libkdenetwork/libgpgme-copy/configure.in.in new file mode 100644 index 000000000..afcc995c2 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/configure.in.in @@ -0,0 +1,364 @@ +# configure.in for GPGME +# Copyright (C) 2000 Werner Koch (dd9jn) +# Copyright (C) 2001, 2002, 2003 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# (Process this file with autoconf to produce a configure script.) + +#AC_PREREQ(2.57) +#min_automake_version="1.7.6" + +# Version number: Remember to change it immediately *after* a release. +#AC_INIT(gpgme, 0.4.4, [bug-gpgme@gnupg.org]) +# LT Version numbers, remember to change them just *before* a release. +# (Code changed: REVISION++) +# (Interfaces added/removed/changed: CURRENT++, REVISION=0) +# (Interfaces added: AGE++) +# (Interfaces removed: AGE=0) +# +#LIBGPGME_LT_CURRENT=12 +#LIBGPGME_LT_AGE=1 +#LIBGPGME_LT_REVISION=1 +NEED_GPG_VERSION=1.2.2 +NEED_GPGSM_VERSION=1.9.3 +############################################## +#AC_PREREQ(2.52) +#AC_REVISION($Revision$) + +#PACKAGE=$PACKAGE_NAME +#VERSION=$PACKAGE_VERSION + +#AC_CONFIG_SRCDIR(gpgme/gpgme.h) +#AM_CONFIG_HEADER(config.h) +#AM_INIT_AUTOMAKE($PACKAGE, $VERSION) +#AM_MAINTAINER_MODE +#AC_CANONICAL_HOST + +AH_VERBATIM([_GNU_SOURCE], +[/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif]) + +dnl AH_VERBATIM([_REENTRANT], +dnl [/* To allow the use of GPGME in multithreaded programs we have to use +dnl special features from the library. +dnl IMPORTANT: gpgme is not yet fully reentrant and you should use it +dnl only from one thread. */ +dnl #ifndef _REENTRANT +dnl # define _REENTRANT 1 +dnl #endif]) + + +dnl AC_PROG_CC + + +dnl AC_SUBST(LIBGPGME_LT_CURRENT) +dnl AC_SUBST(LIBGPGME_LT_AGE) +dnl AC_SUBST(LIBGPGME_LT_REVISION) +AC_DEFINE_UNQUOTED(NEED_GPG_VERSION, "$NEED_GPG_VERSION", + [Min. needed GnuPG version.]) +AC_DEFINE_UNQUOTED(NEED_GPGSM_VERSION, "$NEED_GPGSM_VERSION", + [Min. needed GPGSM version.]) + +dnl AC_SUBST(PACKAGE) +dnl AC_SUBST(VERSION) +dnl AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package]) +dnl AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package]) + +# Don't default to build static libs. +dnl AC_DISABLE_STATIC +dnl AC_PROG_LIBTOOL + +dnl # For now we hardcode the use of version scripts. It would be better +dnl # to write a test for this or even implement this within libtool. +dnl have_ld_version_script=no +dnl case "${host}" in +dnl *-*-linux*) +dnl have_ld_version_script=yes +dnl ;; +dnl *-*-gnu*) +dnl have_ld_version_script=yes +dnl ;; +dnl esac +dnl AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes") + +GPG_DEFAULT=no +GPGSM_DEFAULT=no +component_system=None +case "${host}" in + *-*-mingw32* | i?86-emx-os2 | i?86-*-os2*emx | i?86-*-msdosdjgpp* ) + # special stuff for Windoze NT + # OS/2 with the EMX environment + # DOS with the DJGPP environment + AC_DEFINE(HAVE_DRIVE_LETTERS, , + [Defined if we run on some of the PCDOS like systems (DOS, + Windoze, OS/2) with special properties like no file modes.]) + AC_DEFINE(HAVE_DOSISH_SYSTEM, , + [Defined if the filesystem uses driver letters.]) + have_dosish_system=yes + GPG_DEFAULT='c:\\gnupg\\gpg.exe' + # XXX Assuan is not supported in this configuration. + #GPGSM_DEFAULT='c:\\gnupg\\gpgsm.exe' + #component_system='COM+' + ;; + *) +dnl AC_CHECK_PTH(1.2.0,,,no,have_pth=yes) +dnl if test "$have_pth" = yes; then +dnl AC_DEFINE(HAVE_PTH, ,[Define if we have Pth.]) +dnl CFLAGS="$CFLAGS $PTH_CFLAGS" +dnl fi +dnl AC_CHECK_LIB(pthread,pthread_create,have_pthread=yes) +dnl if test "$have_pthread" = yes; then +dnl AC_DEFINE(HAVE_PTHREAD, ,[Define if we have pthread.]) +dnl fi + + # XXX: Probably use exec-prefix here? +# GPG_DEFAULT='/usr/bin/gpg' +# GPGSM_DEFAULT='/usr/bin/gpgsm' + ;; +esac + +if test "$have_dosish_system" = yes; then + AC_DEFINE(HAVE_DOSISH_SYSTEM,1, + [Defined if we run on some of the PCDOS like systems· + (DOS, Windoze. OS/2) with special properties like + no file modes]) +fi +AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = "yes") +dnl AM_CONDITIONAL(HAVE_PTH, test "$have_pth" = "yes") +dnl AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes") +dnl dnl + +# Checks for header files. +AC_CHECK_HEADERS(sys/select.h) + + +# Type checks. +AC_CHECK_SIZEOF(unsigned int) + + +# Checks for compiler features. +dnl if test "$GCC" = yes; then +dnl GPGME_OWN_CFLAGS="-Wall -Wcast-align -Wshadow -Wstrict-prototypes" +dnl else +dnl GPGME_OWN_CFLAGS="" +dnl fi +dnl AC_SUBST(GPGME_OWN_CFLAGS) + + +# Checks for library functions. +AC_CHECK_FUNCS(stpcpy) + +AC_CHECK_FUNCS(vasprintf) +if test "$ac_cv_func_vasprintf" != yes; then + GNUPG_CHECK_VA_COPY +fi + +# Try to find a thread-safe version of getenv(). +have_thread_safe_getenv=no + +dnl Definition of jm_GLIBC21 inlined: + AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, + ac_cv_gnu_library_2_1, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include <features.h> +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2_1=yes, + ac_cv_gnu_library_2_1=no) + ] + ) + AC_SUBST(GLIBC21) + GLIBC21="$ac_cv_gnu_library_2_1" + +dnl + +if test $GLIBC21 = yes; then + have_thread_safe_getenv=yes +fi +if test $have_thread_safe_getenv = yes; then + AC_DEFINE(HAVE_THREAD_SAFE_GETENV, [1], [Define if getenv() is thread-safe]) +fi +have_getenv_r=no +AC_CHECK_FUNCS(getenv_r, have_getenv_r=yes) +if test $have_getenv_r = no && test $have_thread_safe_getenv = no; then + AC_MSG_WARN([ +*** +*** getenv() is not thread-safe and getenv_r() does not exist +***]) +fi + +# For converting time strings to seconds since Epoch, we need the timegm +# function. +AC_CHECK_FUNCS(timegm) +if test "$ac_cv_func_timegm" != yes; then + AC_MSG_WARN([ +*** +*** timegm() not available - a non-thread-safe kludge will be used +*** and the TZ variable might be changed at runtime. +***]) +fi + +# Add a few constants to help porting to W32 +AH_VERBATIM([SEPCONSTANTS], +[ +/* Separators as used in file names and $PATH. Please note that the + string version must not contain more than one character because + the using code assumes strlen()==1 */ +#ifdef HAVE_DOSISH_SYSTEM +#define DIRSEP_C '\\\\' +#define EXTSEP_C '.' +#define DIRSEP_S "\\\\" +#define EXTSEP_S "." +#define PATHSEP_C ';' +#define PATHSEP_S ";" +#else +#define DIRSEP_C '/' +#define EXTSEP_C '.' +#define DIRSEP_S "/" +#define EXTSEP_S "." +#define PATHSEP_C ':' +#define PATHSEP_S ":" +#endif +]) + +AH_BOTTOM([ +/* Definition of GCC specific attributes. */ +#if __GNUC__ > 2 +# define GPGME_GCC_A_PURE __attribute__ ((__pure__)) +#else +# define GPGME_GCC_A_PURE +#endif +]) + +dnl # Checking for libgpg-error. +dnl AM_PATH_GPG_ERROR(0.5,, AC_MSG_ERROR([libgpg-error was not found])) +dnl AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_GPGME, +dnl [The default error source for GPGME.]) + + + +# Checks for system services +NO_OVERRIDE=no +AC_ARG_WITH(gpg, + AC_HELP_STRING([--with-gpg=PATH], [use GnuPG binary at PATH]), + GPG=$withval, NO_OVERRIDE=yes) +if test "$NO_OVERRIDE" = "yes" || test "$GPG" = "yes"; then + GPG= + NO_OVERRIDE=yes + if test "$cross_compiling" != "yes"; then + AC_PATH_PROG(GPG, gpg) + fi + if test -z "$GPG"; then + GPG="$GPG_DEFAULT" + fi +fi +if test "$GPG" = no; then + if test "$NO_OVERRIDE" = "yes"; then + if test "$cross_compiling" != "yes"; then + AC_MSG_WARN([ +*** +*** Could not find GnuPG, install GnuPG or use --with-gpg=PATH to enable it +***]) + else + AC_MSG_ERROR([ +*** +*** Can not determine path to GnuPG when cross-compiling, use --with-gpg=PATH +***]) + fi + fi +else + AC_DEFINE_UNQUOTED(GPG_PATH, "$GPG", [Path to the GnuPG binary.]) + AC_SUBST(GPG) +fi +AM_CONDITIONAL(RUN_GPG_TESTS, + [test "$cross_compiling" != "yes" && test -n "$GPG" && test -r "$GPG"]) +AC_SUBST(GPG_PATH) + +NO_OVERRIDE=no +AC_ARG_WITH(gpgsm, + AC_HELP_STRING([--with-gpgsm=PATH], [use GpgSM binary at PATH]), + GPGSM=$withval, NO_OVERRIDE=yes) +if test "$NO_OVERRIDE" = "yes" || test "$GPGSM" = "yes"; then + GPGSM= + NO_OVERRIDE=yes + if test "$cross_compiling" != "yes"; then + AC_PATH_PROG(GPGSM, gpgsm) + fi + if test -z "$GPGSM"; then + GPGSM="$GPGSM_DEFAULT" + fi +fi +if test "$GPGSM" = no; then + if test "$NO_OVERRIDE" = "yes"; then + if test "$cross_compiling" != "yes"; then + AC_MSG_WARN([ +*** +*** Could not find GpgSM, install GpgSM or use --with-gpgsm=PATH to enable it +***]) + else + AC_MSG_ERROR([ +*** +*** Can not determine path to GpgSM when cross-compiling, use --with-gpgsm=PATH +***]) + fi + fi +else + AC_DEFINE_UNQUOTED(GPGSM_PATH, "$GPGSM", [Path to the GPGSM binary.]) + AC_SUBST(GPGSM) +fi +AM_CONDITIONAL(HAVE_GPGSM, [test -n "$GPGSM" && test -r "$GPGSM"]) +dnl AM_CONDITIONAL(RUN_GPGSM_TESTS, +dnl [test "$cross_compiling" != "yes" && test -n "$GPGSM" && test -r "$GPGSM"]) + +dnl # FIXME: Only build if supported. +dnl AM_CONDITIONAL(BUILD_ASSUAN, test "$GPGSM" != "no") + +AC_CHECK_FUNCS(funopen) + +if test "$GPGSM" != "no"; then + if test $ac_cv_func_funopen != yes; then + # No funopen but we can implement that in terms of fopencookie. + AC_CHECK_FUNCS(fopencookie, funopen, AC_MSG_ERROR([[No implementation of fopencookie or funopen available.]])) + fi + + dnl it's a #define !!! + dnl AC_CHECK_FUNCS(isascii) + + AC_CHECK_FUNCS(putc_unlocked) + AC_CHECK_FUNCS(memrchr) +fi + +# More assuan checks. +AC_CHECK_HEADERS([sys/uio.h]) + +echo " + GPGME v${VERSION} has been configured as follows: + + GnuPG version: min. $NEED_GPG_VERSION + GnuPG path: $GPG + + GpgSM version: min. $NEED_GPGSM_VERSION + GpgSM path: $GPGSM +" diff --git a/libkdenetwork/libgpgme-copy/gpgme/ChangeLog b/libkdenetwork/libgpgme-copy/gpgme/ChangeLog new file mode 100644 index 000000000..5c31489ee --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ChangeLog @@ -0,0 +1,5312 @@ +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-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-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-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-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-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-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-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-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-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-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-27 Marcus Brinkmann <marcus@g10code.de> + + * gpgme.h: Fix documentation of key attribute retrieval functions. + +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> + + * 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> + + * 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> + + * 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 shoudl a coder + test his fix :-) + + * w32-io.c: Does now use reader threads, so that we can use + WaitForMultipleObjects. + * sema.h, posix-sema.c, w32-sema.c: Support for Critcial sections. + Does currently only work for W32. + + * debug.c, util.h : New. Changed all fprintfs to use this new + set of debugging functions. + +2001-01-23 Werner Koch <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 2001, 2002, 2003, 2004, 2005 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/libkdenetwork/libgpgme-copy/gpgme/Makefile.am b/libkdenetwork/libgpgme-copy/gpgme/Makefile.am new file mode 100644 index 000000000..5ea41e091 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/Makefile.am @@ -0,0 +1,50 @@ +# Copyright (C) 2000 Werner Koch (dd9jn) +# Copyright (C) 2001, 2002, 2003 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +## Process this file with automake to produce Makefile.in + +noinst_LTLIBRARIES = libgpgme-real.la libgpgme.la + +assuan_cppflags = -I$(srcdir)/../assuan +assuan_libobjs = ../assuan/libassuan.la + +libgpgme_real_la_SOURCES = \ + conversion.c get-env.c \ + data.c data-fd.c data-stream.c data-mem.c data-user.c \ + data-compat.c \ + signers.c \ + wait.c wait-global.c wait-private.c wait-user.c \ + op-support.c \ + encrypt.c encrypt-sign.c decrypt.c decrypt-verify.c verify.c \ + sign.c passphrase.c progress.c \ + key.c keylist.c trust-item.c trustlist.c \ + import.c export.c genkey.c delete.c edit.c \ + engine.c rungpg.c \ + posix-util.c posix-sema.c posix-io.c \ + engine-gpgsm.c sig-notation.c funopen.c \ + debug.c gpgme.c version.c error.c + +libgpgme_la_SOURCES = ath.c + +AM_CPPFLAGS = $(assuan_cppflags) -I$(srcdir)/../../libgpg-error-copy -I../../libgpg-error-copy + +libgpgme_la_LIBADD = libgpgme-real.la ../../libgpg-error-copy/libgpg-error.la $(assuan_libobjs) + +status-table.h : $(srcdir)/gpgme.h + $(srcdir)/mkstatus < $(srcdir)/gpgme.h > status-table.h diff --git a/libkdenetwork/libgpgme-copy/gpgme/ath-pth-compat.c b/libkdenetwork/libgpgme-copy/gpgme/ath-pth-compat.c new file mode 100644 index 000000000..7bdea8762 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath-pth-compat.c @@ -0,0 +1,123 @@ +/* ath-pth.c - Pth module for self-adapting thread-safeness library + * Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <errno.h> +#include <pth.h> + +#include "ath.h" + +#pragma weak pth_mutex_init +#pragma weak pth_mutex_acquire +#pragma weak pth_mutex_release +#pragma weak pth_read +#pragma weak pth_write +#pragma weak pth_select +#pragma weak pth_waitpid +#pragma weak pth_accept +#pragma weak pth_connect + +/* The lock we take while checking for lazy lock initialization. */ +static pth_mutex_t check_init_lock = PTH_MUTEX_INIT; + +/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if + it is not already initialized. */ +static int +mutex_pth_init (void **priv, int just_check) +{ + int err = 0; + + if (just_check) + pth_mutex_acquire (&check_init_lock, 0, NULL); + if (!*priv || !just_check) + { + pth_mutex_t *lock = malloc (sizeof (pth_mutex_t)); + if (!lock) + err = ENOMEM; + if (!err) + { + err = pth_mutex_init (lock); + if (err == FALSE) + err = errno; + else + err = 0; + + if (err) + free (lock); + else + *priv = lock; + } + } + if (just_check) + pth_mutex_release (&check_init_lock); + return err; +} + + +static int +mutex_pth_destroy (void *priv) +{ + free (priv); + return 0; +} + + +static int +mutex_pth_lock (void *priv) +{ + int ret = pth_mutex_acquire ((pth_mutex_t *) priv, 0, NULL); + return ret == FALSE ? errno : 0; +} + + +static int +mutex_pth_unlock (void *priv) +{ + int ret = pth_mutex_release ((pth_mutex_t *) priv); + return ret == FALSE ? errno : 0; +} + + +static struct ath_ops ath_pth_ops = + { + mutex_pth_init, + mutex_pth_destroy, + mutex_pth_lock, + mutex_pth_unlock, + pth_read, + pth_write, + pth_select, + pth_waitpid, + pth_accept, + pth_connect, + NULL, /* FIXME: When GNU PTh has sendmsg. */ + NULL /* FIXME: When GNU PTh has recvmsg. */ + }; + + +struct ath_ops * +ath_pth_available (void) +{ + if (pth_mutex_init && pth_mutex_acquire && pth_mutex_release + && pth_read && pth_write && pth_select && pth_waitpid) + return &ath_pth_ops; + else + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/ath-pth.c b/libkdenetwork/libgpgme-copy/gpgme/ath-pth.c new file mode 100644 index 000000000..4c883a34a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath-pth.c @@ -0,0 +1,178 @@ +/* ath-pth.c - Pth 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> + +#include <pth.h> + +#include "ath.h" + + +/* The lock we take while checking for lazy lock initialization. */ +static pth_mutex_t check_init_lock = PTH_MUTEX_INIT; + +/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if + it is not already initialized. */ +static int +mutex_pth_init (ath_mutex_t *priv, int just_check) +{ + int err = 0; + + if (just_check) + pth_mutex_acquire (&check_init_lock, 0, NULL); + if (!*priv || !just_check) + { + pth_mutex_t *lock = malloc (sizeof (pth_mutex_t)); + if (!lock) + err = ENOMEM; + if (!err) + { + err = pth_mutex_init (lock); + if (err == FALSE) + err = errno; + else + err = 0; + + if (err) + free (lock); + else + *priv = (ath_mutex_t) lock; + } + } + if (just_check) + pth_mutex_release (&check_init_lock); + return err; +} + + +void +ath_init (void) +{ + /* Nothing to do. */ +} + + +int +ath_mutex_init (ath_mutex_t *lock) +{ + return mutex_pth_init (lock, 0); +} + + +int +ath_mutex_destroy (ath_mutex_t *lock) +{ + int err = mutex_pth_init (lock, 1); + if (!err) + { + /* GNU Pth has no destructor function. */ + free (*lock); + } + return err; +} + + +int +ath_mutex_lock (ath_mutex_t *lock) +{ + int ret = mutex_pth_init (lock, 1); + if (ret) + return ret; + + ret = pth_mutex_acquire ((pth_mutex_t *) *lock, 0, NULL); + return ret == FALSE ? errno : 0; +} + + +int +ath_mutex_unlock (ath_mutex_t *lock) +{ + int ret = mutex_pth_init (lock, 1); + if (ret) + return ret; + + ret = pth_mutex_release ((pth_mutex_t *) *lock); + return ret == FALSE ? errno : 0; +} + + +ssize_t +ath_read (int fd, void *buf, size_t nbytes) +{ + return pth_read (fd, buf, nbytes); +} + + +ssize_t +ath_write (int fd, const void *buf, size_t nbytes) +{ + return pth_write (fd, buf, nbytes); +} + + +ssize_t +ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout) +{ + return pth_select (nfd, rset, wset, eset, timeout); +} + + +ssize_t +ath_waitpid (pid_t pid, int *status, int options) +{ + return pth_waitpid (pid, status, options); +} + + +int +ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr) +{ + return pth_accept (s, addr, length_ptr); +} + + +int +ath_connect (int s, const struct sockaddr *addr, socklen_t length) +{ + return pth_connect (s, addr, length); +} + +int +ath_sendmsg (int s, const struct msghdr *msg, int flags) +{ + /* FIXME: GNU Pth is missing pth_sendmsg. */ + return sendmsg (s, msg, flags); +} + + +int +ath_recvmsg (int s, struct msghdr *msg, int flags) +{ + /* FIXME: GNU Pth is missing pth_recvmsg. */ + return recvmsg (s, msg, flags); +} + diff --git a/libkdenetwork/libgpgme-copy/gpgme/ath-pthread-compat.c b/libkdenetwork/libgpgme-copy/gpgme/ath-pthread-compat.c new file mode 100644 index 000000000..b65fa0514 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath-pthread-compat.c @@ -0,0 +1,104 @@ +/* ath-pthread.c - pthread module for self-adapting thread-safeness library + * Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> + +#include "ath.h" + +/* Need to include pthread_create in our check, as the GNU C library + has the pthread_mutex_* functions in their public interface. */ +#pragma weak pthread_create +#pragma weak pthread_mutex_init +#pragma weak pthread_mutex_destroy +#pragma weak pthread_mutex_lock +#pragma weak pthread_mutex_unlock + +/* The lock we take while checking for lazy lock initialization. */ +static pthread_mutex_t check_init_lock = PTHREAD_MUTEX_INITIALIZER; + +/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if + it is not already initialized. */ +static int +mutex_pthread_init (void **priv, int just_check) +{ + int err = 0; + + if (just_check) + pthread_mutex_lock (&check_init_lock); + if (!*priv || !just_check) + { + pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t)); + if (!lock) + err = ENOMEM; + if (!err) + { + err = pthread_mutex_init (lock, NULL); + if (err) + free (lock); + else + *priv = lock; + } + } + if (just_check) + pthread_mutex_unlock (&check_init_lock); + return err; +} + + +static int +mutex_pthread_destroy (void *priv) +{ + int err = pthread_mutex_destroy ((pthread_mutex_t *) priv); + free (priv); + return err; +} + + +static struct ath_ops ath_pthread_ops = + { + mutex_pthread_init, + mutex_pthread_destroy, + (int (*) (void *)) pthread_mutex_lock, + (int (*) (void *)) pthread_mutex_unlock, + NULL, /* read */ + NULL, /* write */ + NULL, /* select */ + NULL, /* waitpid */ + NULL, /* accept */ + NULL, /* connect */ + NULL, /* sendmsg */ + NULL /* recvmsg */ + }; + + +struct ath_ops * +ath_pthread_available (void) +{ + /* Need to include pthread_create in our check, as the GNU C library + has the pthread_mutex_* functions in their public interface. */ + if (pthread_create + && pthread_mutex_init && pthread_mutex_destroy + && pthread_mutex_lock && pthread_mutex_unlock) + return &ath_pthread_ops; + else + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/ath-pthread.c b/libkdenetwork/libgpgme-copy/gpgme/ath-pthread.c new file mode 100644 index 000000000..b201f089b --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath-pthread.c @@ -0,0 +1,175 @@ +/* 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> +#include <unistd.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#else +# include <sys/time.h> +#endif +#include <sys/types.h> +#include <sys/wait.h> + +#include <pthread.h> + +#include "ath.h" + + +/* The lock we take while checking for lazy lock initialization. */ +static pthread_mutex_t check_init_lock = PTHREAD_MUTEX_INITIALIZER; + +/* Initialize the mutex *PRIV. If JUST_CHECK is true, only do this if + it is not already initialized. */ +static int +mutex_pthread_init (ath_mutex_t *priv, int just_check) +{ + int err = 0; + + if (just_check) + pthread_mutex_lock (&check_init_lock); + if (!*priv || !just_check) + { + pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t)); + if (!lock) + err = ENOMEM; + if (!err) + { + err = pthread_mutex_init (lock, NULL); + if (err) + free (lock); + else + *priv = (ath_mutex_t) lock; + } + } + if (just_check) + pthread_mutex_unlock (&check_init_lock); + return err; +} + + +void +ath_init (void) +{ + /* Nothing to do. */ +} + + +int +ath_mutex_init (ath_mutex_t *lock) +{ + return mutex_pthread_init (lock, 0); +} + + +int +ath_mutex_destroy (ath_mutex_t *lock) +{ + int err = mutex_pthread_init (lock, 1); + if (!err) + { + err = pthread_mutex_destroy ((pthread_mutex_t *) *lock); + free (*lock); + } + return err; +} + + +int +ath_mutex_lock (ath_mutex_t *lock) +{ + int ret = mutex_pthread_init (lock, 1); + if (ret) + return ret; + + return pthread_mutex_lock ((pthread_mutex_t *) *lock); +} + + +int +ath_mutex_unlock (ath_mutex_t *lock) +{ + int ret = mutex_pthread_init (lock, 1); + if (ret) + return ret; + + return pthread_mutex_unlock ((pthread_mutex_t *) *lock); +} + + +ssize_t +ath_read (int fd, void *buf, size_t nbytes) +{ + return read (fd, buf, nbytes); +} + + +ssize_t +ath_write (int fd, const void *buf, size_t nbytes) +{ + return write (fd, buf, nbytes); +} + + +ssize_t +ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout) +{ + return select (nfd, rset, wset, eset, timeout); +} + + +ssize_t +ath_waitpid (pid_t pid, int *status, int options) +{ + return waitpid (pid, status, options); +} + + +int +ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr) +{ + return accept (s, addr, length_ptr); +} + + +int +ath_connect (int s, const struct sockaddr *addr, socklen_t length) +{ + return connect (s, addr, length); +} + +int +ath_sendmsg (int s, const struct msghdr *msg, int flags) +{ + return sendmsg (s, msg, flags); +} + + +int +ath_recvmsg (int s, struct msghdr *msg, int flags) +{ + return recvmsg (s, msg, flags); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/ath.c b/libkdenetwork/libgpgme-copy/gpgme/ath.c new file mode 100644 index 000000000..dda7c3188 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath.c @@ -0,0 +1,169 @@ +/* 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> +#include <unistd.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#else +# include <sys/time.h> +#endif +#include <sys/types.h> +#ifndef HAVE_W32_SYSTEM +#include <sys/wait.h> +#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) + + +int +ath_mutex_init (ath_mutex_t *lock) +{ +#ifndef NDEBUG + *lock = MUTEX_UNLOCKED; +#endif + return 0; +} + + +int +ath_mutex_destroy (ath_mutex_t *lock) +{ +#ifndef NDEBUG + assert (*lock == MUTEX_UNLOCKED); + + *lock = MUTEX_DESTROYED; +#endif + return 0; +} + + +int +ath_mutex_lock (ath_mutex_t *lock) +{ +#ifndef NDEBUG + assert (*lock == MUTEX_UNLOCKED); + + *lock = MUTEX_LOCKED; +#endif + return 0; +} + + +int +ath_mutex_unlock (ath_mutex_t *lock) +{ +#ifndef NDEBUG + assert (*lock == MUTEX_LOCKED); + + *lock = MUTEX_UNLOCKED; +#endif + return 0; +} + + +ssize_t +ath_read (int fd, void *buf, size_t nbytes) +{ + return read (fd, buf, nbytes); +} + + +ssize_t +ath_write (int fd, const void *buf, size_t nbytes) +{ + return write (fd, buf, nbytes); +} + + +ssize_t +ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, + struct timeval *timeout) +{ +#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/libkdenetwork/libgpgme-copy/gpgme/ath.h b/libkdenetwork/libgpgme-copy/gpgme/ath.h new file mode 100644 index 000000000..7491f72e4 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ath.h @@ -0,0 +1,89 @@ +/* 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_W32_SYSTEM + /* fixme: Check how we did it in libgcrypt. */ + struct msghdr { int dummy; }; + typedef int socklen_t; +# include <windows.h> +# include <io.h> + +#else /*!HAVE_W32_SYSTEM*/ + +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# include <sys/time.h> +# endif +# include <sys/types.h> +# 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; + +/* 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/libkdenetwork/libgpgme-copy/gpgme/context.h b/libkdenetwork/libgpgme-copy/gpgme/context.h new file mode 100644 index 000000000..e7e2afa44 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/context.h @@ -0,0 +1,118 @@ +/* context.h - Definitions for a GPGME context. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 CONTEXT_H +#define CONTEXT_H + +#include "gpgme.h" +#include "engine.h" +#include "wait.h" + + +/* Operations might require to remember arbitrary information and data + objects during invocations of the status handler. The + ctx_op_data structure provides a generic framework to hook in + such additional data. */ +typedef enum + { + OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE, + OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT, + OPDATA_VERIFY, OPDATA_TRUSTLIST + } ctx_op_data_id_t; + + +struct ctx_op_data +{ + /* The next element in the linked list, or NULL if this is the last + element. */ + struct ctx_op_data *next; + + /* The type of the hook data, which can be used by a routine to + lookup the hook data. */ + ctx_op_data_id_t type; + + /* The function to release HOOK and all its associated resources. + Can be NULL if no special dealllocation routine is necessary. */ + void (*cleanup) (void *hook); + + /* The hook that points to the operation data. */ + void *hook; +}; +typedef struct ctx_op_data *ctx_op_data_t; + + +/* The context defines an environment in which crypto operations can + be performed (sequentially). */ +struct gpgme_context +{ + /* The 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; + + /* 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/libkdenetwork/libgpgme-copy/gpgme/conversion.c b/libkdenetwork/libgpgme-copy/gpgme/conversion.c new file mode 100644 index 000000000..bba62bde3 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/conversion.c @@ -0,0 +1,414 @@ +/* conversion.c - String conversion helper 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 <time.h> +#include <errno.h> + +#include "gpgme.h" +#include "util.h" + + +#define atoi_1(p) (*(p) - '0' ) +#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) +#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) + + + +/* Convert two hexadecimal digits from STR to the value they + represent. Returns -1 if one of the characters is not a + hexadecimal digit. */ +int +_gpgme_hextobyte (const char *str) +{ + int val = 0; + int i; + +#define NROFHEXDIGITS 2 + for (i = 0; i < NROFHEXDIGITS; i++) + { + if (*str >= '0' && *str <= '9') + val += *str - '0'; + else if (*str >= 'A' && *str <= 'F') + val += 10 + *str - 'A'; + else if (*str >= 'a' && *str <= 'f') + val += 10 + *str - 'a'; + else + return -1; + if (i < NROFHEXDIGITS - 1) + val *= 16; + str++; + } + return val; +} + + +/* Decode the C formatted string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. */ +gpgme_error_t +_gpgme_decode_c_string (const char *src, char **destp, size_t len) +{ + char *dest; + + /* Set up the destination buffer. */ + if (len) + { + if (len < strlen (src) + 1) + return gpg_error (GPG_ERR_INTERNAL); + + dest = *destp; + } + else + { + /* The converted string will never be larger than the original + string. */ + dest = malloc (strlen (src) + 1); + if (!dest) + return gpg_error_from_errno (errno); + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src != '\\') + { + *(dest++) = *(src++); + continue; + } + + switch (src[1]) + { +#define DECODE_ONE(match,result) \ + case match: \ + src += 2; \ + *(dest++) = result; \ + break; + + DECODE_ONE ('\'', '\''); + DECODE_ONE ('\"', '\"'); + DECODE_ONE ('\?', '\?'); + DECODE_ONE ('\\', '\\'); + DECODE_ONE ('a', '\a'); + DECODE_ONE ('b', '\b'); + DECODE_ONE ('f', '\f'); + DECODE_ONE ('n', '\n'); + DECODE_ONE ('r', '\r'); + DECODE_ONE ('t', '\t'); + DECODE_ONE ('v', '\v'); + + case 'x': + { + int val = _gpgme_hextobyte (&src[2]); + + if (val == -1) + { + /* Should not happen. */ + *(dest++) = *(src++); + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + } + else + { + if (!val) + { + /* A binary zero is not representable in a C + string. */ + *(dest++) = '\\'; + *(dest++) = '0'; + } + else + *((unsigned char *) dest++) = val; + src += 4; + } + } + break; + + default: + { + /* Should not happen. */ + *(dest++) = *(src++); + *(dest++) = *(src++); + } + } + } + *(dest++) = 0; + + return 0; +} + + +/* Decode the percent escaped string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. 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_errno (errno); + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src != '%') + { + *(dest++) = *(src++); + continue; + } + else + { + int val = _gpgme_hextobyte (&src[1]); + + if (val == -1) + { + /* Should not happen. */ + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + } + else + { + if (!val && !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; +} + + +/* Parse the string TIMESTAMP into a time_t. The string may either be + seconds since Epoch or in the ISO 8601 format like + "20390815T143012". Returns 0 for an empty string or seconds since + Epoch. Leading spaces are skipped. If ENDP is not NULL, it will + point to the next non-parsed character in TIMESTRING. */ +time_t +_gpgme_parse_timestamp (const char *timestamp, char **endp) +{ + /* Need to skip leading spaces, because that is what strtoul does + but not our ISO 8601 checking code. */ + while (*timestamp && *timestamp== ' ') + timestamp++; + if (!*timestamp) + return 0; + + if (strlen (timestamp) >= 15 && timestamp[8] == 'T') + { + struct tm buf; + int year; + + year = atoi_4 (timestamp); + if (year < 1900) + return (time_t)(-1); + + /* Fixme: We would better use a configure test to see whether + mktime can handle dates beyond 2038. */ + if (sizeof (time_t) <= 4 && year >= 2038) + return (time_t)2145914603; /* 2037-12-31 23:23:23 */ + + memset (&buf, 0, sizeof buf); + buf.tm_year = year - 1900; + buf.tm_mon = atoi_2 (timestamp+4) - 1; + buf.tm_mday = atoi_2 (timestamp+6); + buf.tm_hour = atoi_2 (timestamp+9); + buf.tm_min = atoi_2 (timestamp+11); + buf.tm_sec = atoi_2 (timestamp+13); + + if (endp) + *endp = (char*)(timestamp + 15); +#ifdef HAVE_TIMEGM + return timegm (&buf); +#else + { + time_t tim; + + putenv ("TZ=UTC"); + tim = mktime (&buf); +#ifdef __GNUC__ +#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway. +#endif + return tim; + } +#endif /* !HAVE_TIMEGM */ + } + else + return (time_t)strtoul (timestamp, endp, 10); +} + + + + +static struct +{ + char *name; + gpgme_error_t err; +} gnupg_errors[] = + { + { "EOF", GPG_ERR_EOF }, + { "No_Error", GPG_ERR_NO_ERROR }, + { "General_Error", GPG_ERR_GENERAL }, + { "Out_Of_Core", GPG_ERR_ENOMEM }, + { "Invalid_Value", GPG_ERR_INV_VALUE }, + { "IO_Error", GPG_ERR_GENERAL }, + { "Resource_Limit", GPG_ERR_RESOURCE_LIMIT }, + { "Internal_Error", GPG_ERR_INTERNAL }, + { "Bad_Certificate", GPG_ERR_BAD_CERT }, + { "Bad_Certificate_Chain", GPG_ERR_BAD_CERT_CHAIN}, + { "Missing_Certificate", GPG_ERR_MISSING_CERT }, + { "No_Data", GPG_ERR_NO_DATA }, + { "Bad_Signature", GPG_ERR_BAD_SIGNATURE }, + { "Not_Implemented", GPG_ERR_NOT_IMPLEMENTED }, + { "Conflict", GPG_ERR_CONFLICT }, + { "Bug", GPG_ERR_BUG }, + { "Read_Error", GPG_ERR_GENERAL }, + { "Write_Error", GPG_ERR_GENERAL }, + { "Invalid_Line", GPG_ERR_GENERAL }, + { "Incomplete_Line", GPG_ERR_INCOMPLETE_LINE }, + { "Invalid_Response", GPG_ERR_INV_RESPONSE }, + { "Agent_Error", GPG_ERR_AGENT }, + { "No_Public_Key", GPG_ERR_NO_PUBKEY }, + { "No_Secret_Key", GPG_ERR_NO_SECKEY }, + { "File_Open_Error", GPG_ERR_GENERAL }, + { "File_Create_Error", GPG_ERR_GENERAL }, + { "File_Error", GPG_ERR_GENERAL }, + { "Not_Supported", GPG_ERR_NOT_SUPPORTED }, + { "Invalid_Data", GPG_ERR_INV_DATA }, + { "Assuan_Server_Fault", GPG_ERR_ASSUAN_SERVER_FAULT }, + { "Assuan_Error", GPG_ERR_ASSUAN }, + { "Invalid_Session_Key", GPG_ERR_INV_SESSION_KEY }, + { "Invalid_Sexp", GPG_ERR_INV_SEXP }, + { "Unsupported_Algorithm", GPG_ERR_UNSUPPORTED_ALGORITHM }, + { "No_PIN_Entry", GPG_ERR_NO_PIN_ENTRY }, + { "PIN_Entry_Error", GPG_ERR_NO_PIN_ENTRY }, + { "Bad_PIN", GPG_ERR_BAD_PIN }, + { "Bad_Passphrase", GPG_ERR_BAD_PASSPHRASE }, + { "Invalid_Name", GPG_ERR_INV_NAME }, + { "Bad_Public_Key", GPG_ERR_BAD_PUBKEY }, + { "Bad_Secret_Key", GPG_ERR_BAD_SECKEY }, + { "Bad_Data", GPG_ERR_BAD_DATA }, + { "Invalid_Parameter", GPG_ERR_INV_PARAMETER }, + { "Tribute_to_D_A", GPG_ERR_TRIBUTE_TO_D_A }, + { "No_Dirmngr", GPG_ERR_NO_DIRMNGR }, + { "Dirmngr_Error", GPG_ERR_DIRMNGR }, + { "Certificate_Revoked", GPG_ERR_CERT_REVOKED }, + { "No_CRL_Known", GPG_ERR_NO_CRL_KNOWN }, + { "CRL_Too_Old", GPG_ERR_CRL_TOO_OLD }, + { "Line_Too_Long", GPG_ERR_LINE_TOO_LONG }, + { "Not_Trusted", GPG_ERR_NOT_TRUSTED }, + { "Canceled", GPG_ERR_CANCELED }, + { "Bad_CA_Certificate", GPG_ERR_BAD_CA_CERT }, + { "Certificate_Expired", GPG_ERR_CERT_EXPIRED }, + { "Certificate_Too_Young", GPG_ERR_CERT_TOO_YOUNG }, + { "Unsupported_Certificate", GPG_ERR_UNSUPPORTED_CERT }, + { "Unknown_Sexp", GPG_ERR_UNKNOWN_SEXP }, + { "Unsupported_Protection", GPG_ERR_UNSUPPORTED_PROTECTION }, + { "Corrupted_Protection", GPG_ERR_CORRUPTED_PROTECTION }, + { "Ambiguous_Name", GPG_ERR_AMBIGUOUS_NAME }, + { "Card_Error", GPG_ERR_CARD }, + { "Card_Reset", GPG_ERR_CARD_RESET }, + { "Card_Removed", GPG_ERR_CARD_REMOVED }, + { "Invalid_Card", GPG_ERR_INV_CARD }, + { "Card_Not_Present", GPG_ERR_CARD_NOT_PRESENT }, + { "No_PKCS15_App", GPG_ERR_NO_PKCS15_APP }, + { "Not_Confirmed", GPG_ERR_NOT_CONFIRMED }, + { "Configuration_Error", GPG_ERR_CONFIGURATION }, + { "No_Policy_Match", GPG_ERR_NO_POLICY_MATCH }, + { "Invalid_Index", GPG_ERR_INV_INDEX }, + { "Invalid_Id", GPG_ERR_INV_ID }, + { "No_Scdaemon", GPG_ERR_NO_SCDAEMON }, + { "Scdaemon_Error", GPG_ERR_SCDAEMON }, + { "Unsupported_Protocol", GPG_ERR_UNSUPPORTED_PROTOCOL }, + { "Bad_PIN_Method", GPG_ERR_BAD_PIN_METHOD }, + { "Card_Not_Initialized", GPG_ERR_CARD_NOT_INITIALIZED }, + { "Unsupported_Operation", GPG_ERR_UNSUPPORTED_OPERATION }, + { "Wrong_Key_Usage", GPG_ERR_WRONG_KEY_USAGE } + }; + + +gpgme_error_t +_gpgme_map_gnupg_error (char *err) +{ + unsigned int i; + + /* Future version of GnuPG might return the error code directly, so + we first test for a a numerical value and use that verbatim. + Note that this numerical value might be followed by an + underschore and the textual representation of the error code. */ + if (*err >= '0' && *err <= '9') + return strtoul (err, NULL, 10); + + /* Well, this is a token, use the mapping table to get the error. + The drawback is that we won't receive an error source and have to + use GPG as source. */ + for (i = 0; i < DIM (gnupg_errors); i++) + if (!strcmp (gnupg_errors[i].name, err)) + return gpg_err_make (GPG_ERR_SOURCE_GPG, gnupg_errors[i].err); + + return gpg_err_make (GPG_ERR_SOURCE_GPG, GPG_ERR_GENERAL); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/data-compat.c b/libkdenetwork/libgpgme-copy/gpgme/data-compat.c new file mode 100644 index 000000000..91fa6bed1 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data-compat.c @@ -0,0 +1,209 @@ +/* data-compat.c - Compatibility interfaces for data objects. + Copyright (C) 2002, 2003, 2004 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU 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 <sys/time.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "data.h" +#include "util.h" + + +/* Create a new data buffer filled with LENGTH bytes starting from + OFFSET within the file FNAME or stream STREAM (exactly one must be + non-zero). */ +gpgme_error_t +gpgme_data_new_from_filepart (gpgme_data_t *dh, const char *fname, + FILE *stream, off_t offset, size_t length) +{ + gpgme_error_t err; + char *buf = NULL; + int res; + + if (stream && fname) + return gpg_error (GPG_ERR_INV_VALUE); + + if (fname) + stream = fopen (fname, "rb"); + if (!stream) + return gpg_error_from_errno (errno); + +#ifdef HAVE_FSEEKO + res = fseeko (stream, offset, SEEK_SET); +#else + /* FIXME: Check for overflow, or at least bail at compilation. */ + res = fseek (stream, offset, SEEK_SET); +#endif + + if (res) + { + int saved_errno = errno; + if (fname) + fclose (stream); + return gpg_error_from_errno (saved_errno); + } + + buf = malloc (length); + if (!buf) + { + int saved_errno = errno; + if (fname) + fclose (stream); + return gpg_error_from_errno (saved_errno); + } + + while (fread (buf, length, 1, stream) < 1 + && ferror (stream) && errno == EINTR); + if (ferror (stream)) + { + int saved_errno = errno; + if (buf) + free (buf); + if (fname) + fclose (stream); + return gpg_error_from_errno (saved_errno); + } + + if (fname) + fclose (stream); + + err = gpgme_data_new (dh); + if (err) + { + if (buf) + free (buf); + return err; + } + + (*dh)->data.mem.buffer = buf; + (*dh)->data.mem.size = length; + (*dh)->data.mem.length = length; + return 0; +} + + +/* Create a new data buffer filled with the content of file FNAME. + COPY must be non-zero (delayed reads are not supported yet). */ +gpgme_error_t +gpgme_data_new_from_file (gpgme_data_t *dh, const char *fname, int copy) +{ + struct stat statbuf; + + if (!fname || !copy) + return gpg_error (GPG_ERR_INV_VALUE); + + if (stat (fname, &statbuf) < 0) + return gpg_error_from_errno (errno); + + return gpgme_data_new_from_filepart (dh, fname, NULL, 0, statbuf.st_size); +} + + +static int +gpgme_error_to_errno (gpgme_error_t err) +{ + int no = gpg_err_code_to_errno (err); + + if (no) + { + errno = no; + return -1; + } + + switch (gpg_err_code (err)) + { + case GPG_ERR_EOF: + return 0; + case GPG_ERR_INV_VALUE: + errno = EINVAL; + return -1; + case GPG_ERR_NOT_SUPPORTED: + errno = ENOSYS; + return -1; + default: + /* FIXME: Yeah, well. */ + errno = EINVAL; + return -1; + } +} + + +static ssize_t +old_user_read (gpgme_data_t dh, void *buffer, size_t size) +{ + size_t amt; + gpgme_error_t err = (*dh->data.old_user.cb) (dh->data.old_user.handle, + buffer, size, &amt); + if (err) + return gpgme_error_to_errno (err); + return amt; +} + + +static off_t +old_user_seek (gpgme_data_t dh, off_t offset, int whence) +{ + gpgme_error_t err; + if (whence != SEEK_SET || offset) + return EINVAL; + err = (*dh->data.old_user.cb) (dh->data.old_user.handle, NULL, 0, NULL); + if (err) + return gpgme_error_to_errno (err); + return 0; +} + + +static struct _gpgme_data_cbs old_user_cbs = + { + old_user_read, + NULL, + old_user_seek, + NULL + }; + + +/* Create a new data buffer which retrieves the data from the callback + function READ_CB. */ +gpgme_error_t +gpgme_data_new_with_read_cb (gpgme_data_t *dh, + int (*read_cb) (void *, char *, size_t, size_t *), + void *read_cb_value) +{ + gpgme_error_t err = _gpgme_data_new (dh, &old_user_cbs); + if (err) + return err; + + (*dh)->data.old_user.cb = read_cb; + (*dh)->data.old_user.handle = read_cb_value; + return 0; +} + + +gpgme_error_t +gpgme_data_rewind (gpgme_data_t dh) +{ + return (gpgme_data_seek (dh, 0, SEEK_SET) == -1) + ? gpg_error_from_errno (errno) : 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/data-fd.c b/libkdenetwork/libgpgme-copy/gpgme/data-fd.c new file mode 100644 index 000000000..2c65be197 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data-fd.c @@ -0,0 +1,78 @@ +/* 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 + +#include <unistd.h> +#include <sys/types.h> + +#include "data.h" + + +static ssize_t +fd_read (gpgme_data_t dh, void *buffer, size_t size) +{ + return read (dh->data.fd, buffer, size); +} + + +static ssize_t +fd_write (gpgme_data_t dh, const void *buffer, size_t size) +{ + return write (dh->data.fd, buffer, size); +} + + +static off_t +fd_seek (gpgme_data_t dh, off_t offset, int whence) +{ + return lseek (dh->data.fd, offset, whence); +} + + +static 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 *dh, int fd) +{ + gpgme_error_t err = _gpgme_data_new (dh, &fd_cbs); + if (err) + return err; + + (*dh)->data.fd = fd; + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/data-mem.c b/libkdenetwork/libgpgme-copy/gpgme/data-mem.c new file mode 100644 index 000000000..c76981166 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data-mem.c @@ -0,0 +1,251 @@ +/* data-mem.c - A memory based data object. + 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 <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <assert.h> +#include <string.h> + +#include "data.h" +#include "util.h" + + +static ssize_t +mem_read (gpgme_data_t dh, void *buffer, size_t size) +{ + size_t amt = dh->data.mem.length - dh->data.mem.offset; + const char *src; + + if (!amt) + return 0; + + if (size < amt) + amt = size; + + src = dh->data.mem.buffer ? dh->data.mem.buffer : dh->data.mem.orig_buffer; + memcpy (buffer, src + dh->data.mem.offset, amt); + dh->data.mem.offset += amt; + return amt; +} + + +static ssize_t +mem_write (gpgme_data_t dh, const void *buffer, size_t size) +{ + size_t unused; + + if (!dh->data.mem.buffer && dh->data.mem.orig_buffer) + { + size_t new_size = dh->data.mem.size; + char *new_buffer; + + if (new_size < dh->data.mem.offset + size) + new_size = dh->data.mem.offset + size; + + new_buffer = malloc (new_size); + if (!new_buffer) + return -1; + memcpy (new_buffer, dh->data.mem.orig_buffer, dh->data.mem.length); + + dh->data.mem.buffer = new_buffer; + dh->data.mem.size = new_size; + } + + unused = dh->data.mem.size - dh->data.mem.offset; + if (unused < size) + { + /* Allocate a large enough buffer with exponential backoff. */ +#define INITIAL_ALLOC 512 + size_t new_size = dh->data.mem.size + ? (2 * dh->data.mem.size) : INITIAL_ALLOC; + char *new_buffer; + + if (new_size < dh->data.mem.offset + size) + new_size = dh->data.mem.offset + size; + + new_buffer = realloc (dh->data.mem.buffer, new_size); + if (!new_buffer && new_size > dh->data.mem.offset + size) + { + /* Maybe we were too greedy, try again. */ + new_size = dh->data.mem.offset + size; + new_buffer = realloc (dh->data.mem.buffer, new_size); + } + if (!new_buffer) + return -1; + dh->data.mem.buffer = new_buffer; + dh->data.mem.size = new_size; + } + + memcpy (dh->data.mem.buffer + dh->data.mem.offset, buffer, size); + dh->data.mem.offset += size; + if (dh->data.mem.length < dh->data.mem.offset) + dh->data.mem.length = dh->data.mem.offset; + return size; +} + + +static off_t +mem_seek (gpgme_data_t dh, off_t offset, int whence) +{ + switch (whence) + { + case SEEK_SET: + if (offset < 0 || offset > dh->data.mem.length) + { + errno = EINVAL; + return -1; + } + dh->data.mem.offset = offset; + break; + case SEEK_CUR: + if ((offset > 0 && dh->data.mem.length - dh->data.mem.offset < offset) + || (offset < 0 && dh->data.mem.offset < -offset)) + { + errno = EINVAL; + return -1; + } + dh->data.mem.offset += offset; + break; + case SEEK_END: + if (offset > 0 || -offset > dh->data.mem.length) + { + errno = EINVAL; + return -1; + } + dh->data.mem.offset = dh->data.mem.length - offset; + break; + default: + errno = EINVAL; + return -1; + } + return dh->data.mem.offset; +} + + +static void +mem_release (gpgme_data_t dh) +{ + if (dh->data.mem.buffer) + free (dh->data.mem.buffer); +} + + +static struct _gpgme_data_cbs mem_cbs = + { + mem_read, + mem_write, + mem_seek, + mem_release, + NULL + }; + + +/* Create a new data buffer and return it in R_DH. */ +gpgme_error_t +gpgme_data_new (gpgme_data_t *dh) +{ + gpgme_error_t err = _gpgme_data_new (dh, &mem_cbs); + if (err) + return err; + + return 0; +} + + +/* Create a new data buffer filled with SIZE bytes starting from + BUFFER. If COPY is zero, copying is delayed until necessary, and + the data is taken from the original location when needed. */ +gpgme_error_t +gpgme_data_new_from_mem (gpgme_data_t *dh, const char *buffer, + size_t size, int copy) +{ + gpgme_error_t err = _gpgme_data_new (dh, &mem_cbs); + if (err) + return err; + + if (copy) + { + char *bufcpy = malloc (size); + if (!bufcpy) + _gpgme_data_release (*dh); + memcpy (bufcpy, buffer, size); + (*dh)->data.mem.buffer = bufcpy; + } + else + (*dh)->data.mem.orig_buffer = buffer; + + (*dh)->data.mem.size = size; + (*dh)->data.mem.length = size; + return 0; +} + + +/* 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; + + if (!dh || dh->cbs != &mem_cbs) + { + gpgme_data_release (dh); + return NULL; + } + + str = dh->data.mem.buffer; + if (!str && dh->data.mem.orig_buffer) + { + str = malloc (dh->data.mem.length); + if (!str) + { + gpgme_data_release (dh); + 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); + + return str; +} + + +/* Release the memory returned by gpgme_data_release_and_get_mem(). */ +void +gpgme_free (void *buffer) +{ + if (buffer) + free (buffer); +} + diff --git a/libkdenetwork/libgpgme-copy/gpgme/data-stream.c b/libkdenetwork/libgpgme-copy/gpgme/data-stream.c new file mode 100644 index 000000000..629fb3630 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data-stream.c @@ -0,0 +1,101 @@ +/* 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> +#include <sys/types.h> + +#include "data.h" + + +static ssize_t +stream_read (gpgme_data_t dh, void *buffer, size_t size) +{ + size_t amt = fread (buffer, 1, size, dh->data.stream); + if (amt > 0) + return amt; + return ferror (dh->data.stream) ? -1 : 0; +} + + +static ssize_t +stream_write (gpgme_data_t dh, const void *buffer, size_t size) +{ + size_t amt = fwrite (buffer, 1, size, dh->data.stream); + if (amt > 0) + return amt; + return ferror (dh->data.stream) ? -1 : 0; +} + + +static off_t +stream_seek (gpgme_data_t dh, off_t offset, int whence) +{ + int err; + +#ifdef HAVE_FSEEKO + err = fseeko (dh->data.stream, offset, whence); +#else + /* FIXME: Check for overflow, or at least bail at compilation. */ + err = fseek (dh->data.stream, offset, whence); +#endif + + if (err) + return -1; + +#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 *dh, FILE *stream) +{ + gpgme_error_t err = _gpgme_data_new (dh, &stream_cbs); + if (err) + return err; + + (*dh)->data.stream = stream; + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/data-user.c b/libkdenetwork/libgpgme-copy/gpgme/data-user.c new file mode 100644 index 000000000..90a0f4210 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data-user.c @@ -0,0 +1,89 @@ +/* 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 + +#include <sys/types.h> +#include <errno.h> + +#include "data.h" + + +static ssize_t +user_read (gpgme_data_t dh, void *buffer, size_t size) +{ + if (!dh->data.user.cbs->read) + return EBADF; + + 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) + return EBADF; + + 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) + return EBADF; + + 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 *dh, gpgme_data_cbs_t cbs, void *handle) +{ + gpgme_error_t err = _gpgme_data_new (dh, &user_cbs); + if (err) + return err; + + (*dh)->data.user.cbs = cbs; + (*dh)->data.user.handle = handle; + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/data.c b/libkdenetwork/libgpgme-copy/gpgme/data.c new file mode 100644 index 000000000..22768ff53 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data.c @@ -0,0 +1,293 @@ +/* data.c - An abstraction for data objects. + Copyright (C) 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include "gpgme.h" +#include "data.h" +#include "util.h" +#include "ops.h" +#include "priv-io.h" + + +gpgme_error_t +_gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs) +{ + gpgme_data_t dh; + + if (!r_dh) + return gpg_error (GPG_ERR_INV_VALUE); + + *r_dh = NULL; + dh = calloc (1, sizeof (*dh)); + if (!dh) + return gpg_error_from_errno (errno); + + dh->cbs = cbs; + + *r_dh = dh; + return 0; +} + + +void +_gpgme_data_release (gpgme_data_t dh) +{ + if (!dh) + 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) +{ + if (!dh) + { + errno = EINVAL; + return -1; + } + if (!dh->cbs->read) + { + errno = ENOSYS; + return -1; + } + return (*dh->cbs->read) (dh, buffer, size); +} + + +/* Write up to SIZE bytes from buffer BUFFER to the data object with + the handle DH. Return the number of characters written, or -1 on + error. If an error occurs, errno is set. */ +ssize_t +gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size) +{ + if (!dh) + { + errno = EINVAL; + return -1; + } + if (!dh->cbs->write) + { + errno = ENOSYS; + return -1; + } + return (*dh->cbs->write) (dh, buffer, size); +} + + +/* Set the current position from where the next read or write starts + in the data object with the handle DH to OFFSET, relativ to + WHENCE. */ +off_t +gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence) +{ + if (!dh) + { + errno = EINVAL; + return -1; + } + if (!dh->cbs->seek) + { + errno = ENOSYS; + return -1; + } + + /* For relative movement, we must take into account the actual + position of the read counter. */ + if (whence == SEEK_CUR) + offset -= dh->pending_len; + + offset = (*dh->cbs->seek) (dh, offset, whence); + if (offset >= 0) + dh->pending_len = 0; + + return offset; +} + + +/* Release the data object with the handle DH. */ +void +gpgme_data_release (gpgme_data_t dh) +{ + if (!dh) + return; + + if (dh->cbs->release) + (*dh->cbs->release) (dh); + _gpgme_data_release (dh); +} + + +/* Get the current encoding meta information for the data object with + handle DH. */ +gpgme_data_encoding_t +gpgme_data_get_encoding (gpgme_data_t dh) +{ + return dh ? dh->encoding : GPGME_DATA_ENCODING_NONE; +} + + +/* Set the encoding meta information for the data object with handle + DH to ENC. */ +gpgme_error_t +gpgme_data_set_encoding (gpgme_data_t dh, gpgme_data_encoding_t enc) +{ + if (!dh) + return gpg_error (GPG_ERR_INV_VALUE); + if (enc < 0 || enc > GPGME_DATA_ENCODING_ARMOR) + return gpg_error (GPG_ERR_INV_VALUE); + dh->encoding = enc; + return 0; +} + + +/* 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) +{ + if (!dh) + return 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 gpg_error_from_errno (errno); + } + else + dh->file_name = 0; + + return 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) + return NULL; + + return dh->file_name; +} + + +/* Functions to support the wait interface. */ + +gpgme_error_t +_gpgme_data_inbound_handler (void *opaque, int fd) +{ + gpgme_data_t dh = (gpgme_data_t) opaque; + char buffer[BUFFER_SIZE]; + char *bufp = buffer; + ssize_t buflen; + + buflen = _gpgme_io_read (fd, buffer, BUFFER_SIZE); + if (buflen < 0) + return gpg_error_from_errno (errno); + if (buflen == 0) + { + _gpgme_io_close (fd); + return 0; + } + + do + { + ssize_t amt = gpgme_data_write (dh, bufp, buflen); + if (amt == 0 || (amt < 0 && errno != EINTR)) + return gpg_error_from_errno (errno); + bufp += amt; + buflen -= amt; + } + while (buflen > 0); + return 0; +} + + +gpgme_error_t +_gpgme_data_outbound_handler (void *opaque, int fd) +{ + gpgme_data_t dh = (gpgme_data_t) opaque; + ssize_t nwritten; + + if (!dh->pending_len) + { + ssize_t amt = gpgme_data_read (dh, dh->pending, BUFFER_SIZE); + if (amt < 0) + return gpg_error_from_errno (errno); + if (amt == 0) + { + _gpgme_io_close (fd); + return 0; + } + dh->pending_len = amt; + } + + nwritten = _gpgme_io_write (fd, dh->pending, dh->pending_len); + if (nwritten == -1 && errno == EAGAIN) + return 0; + + if (nwritten == -1 && errno == EPIPE) + { + /* Not much we can do. The other end closed the pipe, but we + still have data. This should only ever happen if the other + end is going to tell us what happened on some other channel. + Silently close our end. */ + _gpgme_io_close (fd); + return 0; + } + + if (nwritten <= 0) + return gpg_error_from_errno (errno); + + if (nwritten < dh->pending_len) + memmove (dh->pending, dh->pending + nwritten, dh->pending_len - nwritten); + dh->pending_len -= nwritten; + return 0; +} + + +/* 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/libkdenetwork/libgpgme-copy/gpgme/data.h b/libkdenetwork/libgpgme-copy/gpgme/data.h new file mode 100644 index 000000000..370751d5d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/data.h @@ -0,0 +1,132 @@ +/* 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 + +#include <sys/types.h> +#include <limits.h> + +#include "gpgme.h" + + +/* Read up to SIZE bytes into buffer BUFFER from the data object with + the handle DH. Return the number of characters read, 0 on EOF and + -1 on error. If an error occurs, errno is set. */ +typedef ssize_t (*gpgme_data_read_cb) (gpgme_data_t dh, void *buffer, + size_t size); + +/* Write up to SIZE bytes from buffer BUFFER to the data object with + the handle DH. Return the number of characters written, or -1 on + error. If an error occurs, errno is set. */ +typedef ssize_t (*gpgme_data_write_cb) (gpgme_data_t dh, const void *buffer, + size_t size); + +/* Set the current position from where the next read or write starts + in the data object with the handle DH to OFFSET, relativ to + WHENCE. */ +typedef off_t (*gpgme_data_seek_cb) (gpgme_data_t dh, off_t offset, + int whence); + +/* Release the data object with the handle DH. */ +typedef void (*gpgme_data_release_cb) (gpgme_data_t dh); + +/* 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/libkdenetwork/libgpgme-copy/gpgme/debug.c b/libkdenetwork/libgpgme-copy/gpgme/debug.c new file mode 100644 index 000000000..870976c9a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/debug.c @@ -0,0 +1,221 @@ +/* debug.c - helpful output in desperate situations + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <unistd.h> +#include <ctype.h> +#ifndef HAVE_DOSISH_SYSTEM + #include <sys/types.h> + #include <sys/stat.h> + #include <fcntl.h> +#endif +#include <assert.h> + +#include "util.h" +#include "sema.h" + + +/* Lock to serialize initialization of the debug output subsystem and + output of actual debug messages. */ +DEFINE_STATIC_LOCK (debug_lock); + +/* The amount of detail requested by the user, per environment + variable GPGME_DEBUG. */ +static int debug_level; + +/* The output stream for the debug messages. */ +static FILE *errfp; + + +/* Remove leading and trailing white spaces. */ +static char * +trim_spaces (char *str) +{ + char *string, *p, *mark; + + string = str; + /* Find first non space character. */ + for (p = string; *p && isspace (*(unsigned char *) p); p++) + ; + /* Move characters. */ + for (mark = NULL; (*string = *p); string++, p++) + if (isspace (*(unsigned char *) p)) + { + if (!mark) + mark = string; + } + else + mark = NULL; + if (mark) + *mark = '\0'; /* Remove trailing spaces. */ + + return str; +} + + +static void +debug_init (void) +{ + static int initialized; + + LOCK (debug_lock); + if (!initialized) + { + gpgme_error_t err; + char *e; + const char *s1, *s2;; + + err = _gpgme_getenv ("GPGME_DEBUG", &e); + if (err) + { + UNLOCK (debug_lock); + return; + } + + initialized = 1; + errfp = stderr; + if (e) + { + debug_level = atoi (e); + s1 = strchr (e, PATHSEP_C); + if (s1) + { +#ifndef HAVE_DOSISH_SYSTEM + if (getuid () == geteuid ()) + { +#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); + } + + if (debug_level > 0) + fprintf (errfp, "gpgme_debug: level=%d\n", debug_level); + } + UNLOCK (debug_lock); +} + + +/* Log the formatted string FORMAT at debug level LEVEL or higher. */ +void +_gpgme_debug (int level, const char *format, ...) +{ + va_list arg_ptr; + + debug_init (); + if (debug_level < level) + return; + + va_start (arg_ptr, format); + LOCK (debug_lock); + vfprintf (errfp, format, arg_ptr); + va_end (arg_ptr); + if(format && *format && format[strlen (format) - 1] != '\n') + putc ('\n', errfp); + UNLOCK (debug_lock); + fflush (errfp); +} + + +/* Start a new debug line in *LINE, logged at level LEVEL or higher, + and starting with the formatted string FORMAT. */ +void +_gpgme_debug_begin (void **line, int level, const char *format, ...) +{ + va_list arg_ptr; + + debug_init (); + if (debug_level < level) + { + /* Disable logging of this line. */ + *line = NULL; + return; + } + + va_start (arg_ptr, format); + vasprintf ((char **) line, format, arg_ptr); + va_end (arg_ptr); +} + + +/* Add the formatted string FORMAT to the debug line *LINE. */ +void +_gpgme_debug_add (void **line, const char *format, ...) +{ + va_list arg_ptr; + char *toadd; + char *result; + + if (!*line) + return; + + va_start (arg_ptr, format); + vasprintf (&toadd, format, arg_ptr); + va_end (arg_ptr); + asprintf (&result, "%s%s", *(char **) line, toadd); + free (*line); + free (toadd); + *line = result; +} + + +/* Finish construction of *LINE and send it to the debug output + stream. */ +void +_gpgme_debug_end (void **line) +{ + if (!*line) + return; + + /* The smallest possible level is 1, so force logging here by + using that. */ + _gpgme_debug (1, "%s", *line); + free (*line); + *line = NULL; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/debug.h b/libkdenetwork/libgpgme-copy/gpgme/debug.h new file mode 100644 index 000000000..d5a6bbcc9 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/debug.h @@ -0,0 +1,127 @@ +/* debug.h - interface to debugging functions + 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 DEBUG_H +#define DEBUG_H + +#include <string.h> + +/* Remove path components from filenames (i.e. __FILE__) for cleaner + logs. */ +static __inline__ const char *_gpgme_debug_srcname (const char *file); + +static __inline__ const char * +_gpgme_debug_srcname (const char *file) +{ + const char *s = strrchr (file, '/'); + return s? s+1:file; +} + +/* Log the formatted string FORMAT at debug level LEVEL or higher. */ +void _gpgme_debug (int level, const char *format, ...); + +/* Start a new debug line in *LINE, logged at level LEVEL or higher, + and starting with the formatted string FORMAT. */ +void _gpgme_debug_begin (void **helper, int level, const char *format, ...); + +/* Add the formatted string FORMAT to the debug line *LINE. */ +void _gpgme_debug_add (void **helper, const char *format, ...); + +/* Finish construction of *LINE and send it to the debug output + stream. */ +void _gpgme_debug_end (void **helper); + +/* Indirect stringification, requires __STDC__ to work. */ +#define STRINGIFY(v) #v +#define XSTRINGIFY(v) STRINGIFY(v) + +#if 0 +/* Only works in GNU. */ +#define DEBUG(fmt, arg...) \ + _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__) , ##arg) +#define DEBUG_BEGIN(hlp, lvl, fmt, arg...) \ + _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \ + XSTRINGIFY (__LINE__) , ##arg) +#define DEBUG_ADD(hlp, fmt, arg...) \ + _gpgme_debug_add (&(hlp), fmt , ##arg) +#define DEBUG_END(hlp, fmt, arg...) \ + _gpgme_debug_add (&(hlp), fmt , ##arg); \ + _gpgme_debug_end (&(hlp)) +#elif 0 +/* Only works in C99. */ +#define DEBUG0(fmt) \ + _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__)) +#define DEBUG(fmt, ...) \ + _gpgme_debug (1, "%s:%s: " fmt, __FILE__, XSTRINGIFY (__LINE__), __VA_ARGS__) +#define DEBUG_BEGIN(hlp, lvl, fmt) \ + _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \ + XSTRINGIFY (__LINE__)) +#define DEBUG_BEGINX(hlp, lvl, fmt, ...) \ + _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, __FILE__, \ + XSTRINGIFY (__LINE__), __VA_ARGS__) +#define DEBUG_ADD0(hlp, fmt) \ + _gpgme_debug_add (&(hlp), fmt) +#define DEBUG_ADD(hlp, fmt, ...) \ + _gpgme_debug_add (&(hlp), fmt, __VA_ARGS__) +#define DEBUG_END(hlp, fmt) \ + _gpgme_debug_add (&(hlp), fmt); \ + _gpgme_debug_end (&(hlp)) +#define DEBUG_ENDX(hlp, fmt, ...) \ + _gpgme_debug_add (&(hlp), fmt, __VA_ARGS__); \ + _gpgme_debug_end (&(hlp)) +#else +/* This finally works everywhere, horror. */ +#define DEBUG0(fmt) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__)) +#define DEBUG1(fmt,a) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__), (a)) +#define DEBUG2(fmt,a,b) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__), (a), (b)) +#define DEBUG3(fmt,a,b,c) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__), (a), (b), (c)) +#define DEBUG4(fmt,a,b,c,d) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__), (a), (b), (c), (d)) +#define DEBUG5(fmt,a,b,c,d,e) \ + _gpgme_debug (1, "%s:%s: " fmt, _gpgme_debug_srcname (__FILE__), \ + XSTRINGIFY (__LINE__), (a), (b), (c), (d), (e)) +#define DEBUG_BEGIN(hlp,lvl,fmt) \ + _gpgme_debug_begin (&(hlp), lvl, "%s:%s: " fmt, \ + _gpgme_debug_srcname (__FILE__), XSTRINGIFY (__LINE__)) +#define DEBUG_ADD0(hlp,fmt) \ + _gpgme_debug_add (&(hlp), fmt) +#define DEBUG_ADD1(hlp,fmt,a) \ + _gpgme_debug_add (&(hlp), fmt, (a)) +#define DEBUG_ADD2(hlp,fmt,a,b) \ + _gpgme_debug_add (&(hlp), fmt, (a), (b)) +#define DEBUG_ADD3(hlp,fmt,a,b,c) \ + _gpgme_debug_add (&(hlp), fmt, (a), (b), (c)) +#define DEBUG_END(hlp,fmt) \ + _gpgme_debug_add (&(hlp), fmt); \ + _gpgme_debug_end (&(hlp)) +#endif + +#define DEBUG_ENABLED(hlp) (!!(hlp)) + +#endif /* DEBUG_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/decrypt-verify.c b/libkdenetwork/libgpgme-copy/gpgme/decrypt-verify.c new file mode 100644 index 000000000..2fa3bb243 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/decrypt-verify.c @@ -0,0 +1,103 @@ +/* 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 "gpgme.h" +#include "ops.h" + + +static gpgme_error_t +decrypt_verify_status_handler (void *priv, gpgme_status_code_t code, + char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_decrypt_status_handler (priv, code, args); + if (!err) + err = _gpgme_verify_status_handler (priv, code, args); + return err; +} + + +static gpgme_error_t +decrypt_verify_start (gpgme_ctx_t ctx, int synchronous, + gpgme_data_t cipher, gpgme_data_t plain) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_decrypt_init_result (ctx); + if (err) + return err; + + err = _gpgme_op_verify_init_result (ctx); + if (err) + return err; + + if (!cipher) + return gpg_error (GPG_ERR_NO_DATA); + if (!plain) + return gpg_error (GPG_ERR_INV_VALUE); + + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + + _gpgme_engine_set_status_handler (ctx->engine, + decrypt_verify_status_handler, ctx); + + return _gpgme_engine_op_decrypt (ctx->engine, cipher, plain); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx, gpgme_data_t cipher, + gpgme_data_t plain) +{ + return decrypt_verify_start (ctx, 0, cipher, plain); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher, + gpgme_data_t plain) +{ + gpgme_error_t err = decrypt_verify_start (ctx, 1, cipher, plain); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/decrypt.c b/libkdenetwork/libgpgme-copy/gpgme/decrypt.c new file mode 100644 index 000000000..5ce21bad0 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/decrypt.c @@ -0,0 +1,340 @@ +/* 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 "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; + + if (opd->result.unsupported_algorithm) + free (opd->result.unsupported_algorithm); + + if (opd->result.file_name) + free (opd->result.file_name); +} + + +gpgme_decrypt_result_t +gpgme_op_decrypt_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +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_errno (errno); + + 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) + { + 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_OKAY: + opd->okay = 1; + break; + + case GPGME_STATUS_DECRYPTION_FAILED: + opd->failed = 1; + break; + + case GPGME_STATUS_ERROR: + /* Note that this is an informational status code which should + not lead to an error return unless it is something not + related to the backend. */ + { + const char d_alg[] = "decrypt.algorithm"; + const char u_alg[] = "Unsupported_Algorithm"; + const char k_alg[] = "decrypt.keyusage"; + + if (!strncmp (args, d_alg, sizeof (d_alg) - 1)) + { + args += sizeof (d_alg) - 1; + while (*args == ' ') + args++; + + if (!strncmp (args, u_alg, sizeof (u_alg) - 1)) + { + char *end; + + args += sizeof (u_alg) - 1; + while (*args == ' ') + args++; + + end = strchr (args, ' '); + if (end) + *end = '\0'; + + if (!(*args == '?' && *(args + 1) == '\0')) + { + opd->result.unsupported_algorithm = strdup (args); + if (!opd->result.unsupported_algorithm) + return gpg_error_from_errno (errno); + } + } + } + else if (!strncmp (args, k_alg, sizeof (k_alg) - 1)) + { + args += sizeof (k_alg) - 1; + while (*args == ' ') + args++; + + err = _gpgme_map_gnupg_error (args); + if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE) + opd->result.wrong_key_usage = 1; + } + } + break; + + 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) +{ + return decrypt_start (ctx, 0, cipher, plain); +} + + +/* Decrypt ciphertext CIPHER within CTX and store the resulting + plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_decrypt (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain) +{ + gpgme_error_t err = decrypt_start (ctx, 1, cipher, plain); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/delete.c b/libkdenetwork/libgpgme-copy/gpgme/delete.c new file mode 100644 index 000000000..38f2fddb1 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/delete.c @@ -0,0 +1,109 @@ +/* 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 "gpgme.h" +#include "context.h" +#include "ops.h" + + +static gpgme_error_t +delete_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + if (code == GPGME_STATUS_DELETE_PROBLEM) + { + enum delete_problem + { + DELETE_No_Problem = 0, + DELETE_No_Such_Key = 1, + DELETE_Must_Delete_Secret_Key = 2, + DELETE_Ambiguous_Specification = 3 + }; + long problem; + char *tail; + + errno = 0; + problem = strtol (args, &tail, 0); + if (errno || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + + switch (problem) + { + case DELETE_No_Problem: + break; + + case DELETE_No_Such_Key: + return gpg_error (GPG_ERR_NO_PUBKEY); + + case DELETE_Must_Delete_Secret_Key: + return gpg_error (GPG_ERR_CONFLICT); + + case DELETE_Ambiguous_Specification: + return gpg_error (GPG_ERR_AMBIGUOUS_NAME); + + default: + return gpg_error (GPG_ERR_GENERAL); + } + } + return 0; +} + + +static gpgme_error_t +delete_start (gpgme_ctx_t ctx, int synchronous, const gpgme_key_t key, + int allow_secret) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, delete_status_handler, ctx); + + return _gpgme_engine_op_delete (ctx->engine, key, allow_secret); +} + + +/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret + keys are also deleted. */ +gpgme_error_t +gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, + int allow_secret) +{ + return delete_start (ctx, 0, key, allow_secret); +} + + +/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret + keys are also deleted. */ +gpgme_error_t +gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret) +{ + gpgme_error_t err = delete_start (ctx, 1, key, allow_secret); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/edit.c b/libkdenetwork/libgpgme-copy/gpgme/edit.c new file mode 100644 index 000000000..186d4f9de --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/edit.c @@ -0,0 +1,177 @@ +/* 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 "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) +{ + return edit_start (ctx, 0, 0, key, fnc, fnc_value, out); +} + + +/* Edit the key KEY. Send status and command requests to FNC and + output of edit commands to OUT. */ +gpgme_error_t +gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out) +{ + gpgme_error_t err = edit_start (ctx, 1, 0, key, fnc, fnc_value, out); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +gpgme_error_t +gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, + gpgme_data_t out) +{ + return edit_start (ctx, 0, 1, key, fnc, fnc_value, out); +} + + +/* Edit the card for the key KEY. Send status and command requests to + FNC and output of edit commands to OUT. */ +gpgme_error_t +gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out) +{ + gpgme_error_t err = edit_start (ctx, 1, 1, key, fnc, fnc_value, out); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/encrypt-sign.c b/libkdenetwork/libgpgme-copy/gpgme/encrypt-sign.c new file mode 100644 index 000000000..7e3d2ed65 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/encrypt-sign.c @@ -0,0 +1,110 @@ +/* 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 "gpgme.h" +#include "context.h" +#include "ops.h" + + +static gpgme_error_t +encrypt_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_encrypt_status_handler (priv, code, args); + if (!err) + err = _gpgme_sign_status_handler (priv, code, args); + return err; +} + + +static gpgme_error_t +encrypt_sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + if (!plain) + return gpg_error (GPG_ERR_NO_DATA); + if (!cipher || !recp) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_encrypt_init_result (ctx); + if (err) + return err; + + err = _gpgme_op_sign_init_result (ctx); + if (err) + return err; + + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + + _gpgme_engine_set_status_handler (ctx->engine, + encrypt_sign_status_handler, ctx); + + return _gpgme_engine_op_encrypt_sign (ctx->engine, recp, flags, plain, + cipher, ctx->use_armor, + ctx /* FIXME */); +} + + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + store the resulting ciphertext in CIPHER. Also sign the ciphertext + with the signers in CTX. */ +gpgme_error_t +gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + return encrypt_sign_start (ctx, 0, recp, flags, plain, cipher); +} + + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + store the resulting ciphertext in CIPHER. Also sign the ciphertext + with the signers in CTX. */ +gpgme_error_t +gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + gpgme_error_t err = encrypt_sign_start (ctx, 1, recp, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/encrypt.c b/libkdenetwork/libgpgme-copy/gpgme/encrypt.c new file mode 100644 index 000000000..a7a1f4de9 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/encrypt.c @@ -0,0 +1,222 @@ +/* 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 "context.h" +#include "ops.h" + + +typedef struct +{ + struct _gpgme_op_encrypt_result result; + + /* A pointer to the next pointer of the last invalid recipient in + the list. This makes appending new invalid recipients painless + while preserving the order. */ + gpgme_invalid_key_t *lastp; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_invalid_key_t invalid_recipient = opd->result.invalid_recipients; + + while (invalid_recipient) + { + gpgme_invalid_key_t next = invalid_recipient->next; + if (invalid_recipient->fpr) + free (invalid_recipient->fpr); + invalid_recipient = next; + } +} + + +gpgme_encrypt_result_t +gpgme_op_encrypt_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL); + opd = hook; + + if (err || !opd) + return NULL; + + return &opd->result; +} + + +gpgme_error_t +_gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code, + char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_EOF: + if (opd->result.invalid_recipients) + return gpg_error (GPG_ERR_UNUSABLE_PUBKEY); + break; + + case GPGME_STATUS_INV_RECP: + err = _gpgme_parse_inv_recp (args, opd->lastp); + if (err) + return err; + + opd->lastp = &(*opd->lastp)->next; + break; + + case GPGME_STATUS_NO_RECP: + /* Should not happen, because we require at least one recipient. */ + return gpg_error (GPG_ERR_GENERAL); + + default: + break; + } + return 0; +} + + +static gpgme_error_t +encrypt_sym_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_passphrase_status_handler (priv, code, args); + return err; +} + + +static gpgme_error_t +encrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + return _gpgme_progress_status_handler (priv, code, args) + || _gpgme_encrypt_status_handler (priv, code, args); +} + + +gpgme_error_t +_gpgme_op_encrypt_init_result (gpgme_ctx_t ctx) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_ENCRYPT, &hook, sizeof (*opd), + release_op_data); + opd = hook; + if (err) + return err; + + opd->lastp = &opd->result.invalid_recipients; + return 0; +} + + +static gpgme_error_t +encrypt_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + gpgme_error_t err; + int symmetric = 0; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_encrypt_init_result (ctx); + if (err) + return err; + + if (!recp) + symmetric = 1; + + if (!plain) + return gpg_error (GPG_ERR_NO_DATA); + if (!cipher) + return gpg_error (GPG_ERR_INV_VALUE); + if (recp && ! *recp) + return gpg_error (GPG_ERR_INV_VALUE); + + if (symmetric && ctx->passphrase_cb) + { + /* Symmetric encryption requires a passphrase. */ + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + + _gpgme_engine_set_status_handler (ctx->engine, + symmetric + ? encrypt_sym_status_handler + : encrypt_status_handler, + ctx); + + return _gpgme_engine_op_encrypt (ctx->engine, recp, flags, plain, cipher, + ctx->use_armor); +} + + +gpgme_error_t +gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + return encrypt_start (ctx, 0, recp, flags, plain, cipher); +} + + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + store the resulting ciphertext in CIPHER. */ +gpgme_error_t +gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher) +{ + gpgme_error_t err = encrypt_start (ctx, 1, recp, flags, plain, cipher); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/engine-backend.h b/libkdenetwork/libgpgme-copy/gpgme/engine-backend.h new file mode 100644 index 000000000..052e724c2 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/engine-backend.h @@ -0,0 +1,110 @@ +/* engine-backend.h - A crypto backend for the engine interface. + 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 ENGINE_BACKEND_H +#define ENGINE_BACKEND_H + +#include "engine.h" + +/* FIXME: Correct check? */ +#ifdef GPGSM_PATH +#define ENABLE_GPGSM 1 +#endif + +struct engine_ops +{ + /* Static functions. */ + + /* Return the default file name for the binary of this engine. */ + const char *(*get_file_name) (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 (*decrypt) (void *engine, gpgme_data_t ciph, + gpgme_data_t plain); + gpgme_error_t (*delete) (void *engine, gpgme_key_t key, int allow_secret); + gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key, + gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */); + gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, + int use_armor); + gpgme_error_t (*encrypt_sign) (void *engine, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, + int use_armor, gpgme_ctx_t ctx /* FIXME */); + gpgme_error_t (*export) (void *engine, const char *pattern, + unsigned int reserved, gpgme_data_t keydata, + int use_armor); + gpgme_error_t (*export_ext) (void *engine, const char *pattern[], + unsigned int reserved, gpgme_data_t keydata, + int use_armor); + gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor, + gpgme_data_t pubkey, gpgme_data_t seckey); + gpgme_error_t (*import) (void *engine, gpgme_data_t keydata); + gpgme_error_t (*keylist) (void *engine, const char *pattern, + int secret_only, gpgme_keylist_mode_t mode); + gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[], + int secret_only, int reserved, + gpgme_keylist_mode_t mode); + gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out, + gpgme_sig_mode_t mode, int use_armor, + int use_textmode, + int include_certs, gpgme_ctx_t ctx /* FIXME */); + gpgme_error_t (*trustlist) (void *engine, const char *pattern); + gpgme_error_t (*verify) (void *engine, gpgme_data_t sig, + gpgme_data_t signed_text, + gpgme_data_t plaintext); + + void (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs); + void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data); + + gpgme_error_t (*cancel) (void *engine); +}; + + +extern struct engine_ops _gpgme_engine_ops_gpg; /* OpenPGP. */ +#ifdef ENABLE_GPGSM +extern struct engine_ops _gpgme_engine_ops_gpgsm; /* CMS. */ +#endif + +#endif /* ENGINE_BACKEND_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/engine-gpgsm.c b/libkdenetwork/libgpgme-copy/gpgme/engine-gpgsm.c new file mode 100644 index 000000000..7bb71cf24 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/engine-gpgsm.c @@ -0,0 +1,1750 @@ +/* engine-gpgsm.c - GpgSM engine. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef HAVE_W32_SYSTEM + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <assert.h> +#include <unistd.h> +#include <locale.h> +#include <fcntl.h> /* FIXME */ +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "priv-io.h" +#include "sema.h" + +#include "assuan.h" +#include "status-table.h" +#include "debug.h" + +#include "engine-backend.h" + + +typedef struct +{ + int fd; /* FD we talk about. */ + int 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; + + +struct engine_gpgsm +{ + assuan_context_t assuan_ctx; + + int lc_ctype_set; + int lc_messages_set; + + iocb_data_t status_cb; + + /* Input, output etc are from the servers perspective. */ + iocb_data_t input_cb; + + iocb_data_t output_cb; + + iocb_data_t message_cb; + + struct + { + engine_status_handler_t fnc; + void *fnc_value; + } status; + + struct + { + engine_colon_line_handler_t fnc; + void *fnc_value; + struct + { + char *line; + int linesize; + int linelen; + } attic; + int any; /* any data line seen */ + } colon; + + struct gpgme_io_cbs io_cbs; +}; + +typedef struct engine_gpgsm *engine_gpgsm_t; + + +static char * +gpgsm_get_version (const char *file_name) +{ + return _gpgme_get_program_version (file_name ? file_name + : _gpgme_get_gpgsm_path ()); +} + + +static const char * +gpgsm_get_req_version (void) +{ + return NEED_GPGSM_VERSION; +} + + +static void +close_notify_handler (int fd, void *opaque) +{ + engine_gpgsm_t gpgsm = opaque; + + assert (fd != -1); + if (gpgsm->status_cb.fd == fd) + { + if (gpgsm->status_cb.tag) + (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag); + gpgsm->status_cb.fd = -1; + gpgsm->status_cb.tag = NULL; + } + else if (gpgsm->input_cb.fd == fd) + { + if (gpgsm->input_cb.tag) + (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag); + gpgsm->input_cb.fd = -1; + gpgsm->input_cb.tag = NULL; + } + else if (gpgsm->output_cb.fd == fd) + { + if (gpgsm->output_cb.tag) + (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag); + gpgsm->output_cb.fd = -1; + gpgsm->output_cb.tag = NULL; + } + else if (gpgsm->message_cb.fd == fd) + { + if (gpgsm->message_cb.tag) + (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag); + gpgsm->message_cb.fd = -1; + gpgsm->message_cb.tag = NULL; + } +} + + +static gpgme_error_t +map_assuan_error (gpg_error_t err) +{ + if (!err) + return 0; + + if (err == -1) + return gpg_error (GPG_ERR_INV_ENGINE); + + /* New code will use gpg_error_t values. */ + if (gpg_err_source (err)) + return (gpgme_error_t) err; + + /* Legacy code will use old values. */ + switch (err) + { + case ASSUAN_No_Error: + return gpg_error (GPG_ERR_NO_ERROR); + case ASSUAN_General_Error: + return gpg_error (GPG_ERR_GENERAL); + case ASSUAN_Out_Of_Core: + return gpg_error (GPG_ERR_ENOMEM); + case ASSUAN_Invalid_Value: + return gpg_error (GPG_ERR_INV_VALUE); + case ASSUAN_Timeout: + return gpg_error (GPG_ERR_ETIMEDOUT); + case ASSUAN_Read_Error: + return gpg_error (GPG_ERR_GENERAL); + case ASSUAN_Write_Error: + return gpg_error (GPG_ERR_GENERAL); + + case ASSUAN_Problem_Starting_Server: + case ASSUAN_Not_A_Server: + case ASSUAN_Not_A_Client: + case ASSUAN_Nested_Commands: + case ASSUAN_No_Data_Callback: + case ASSUAN_No_Inquire_Callback: + case ASSUAN_Connect_Failed: + case ASSUAN_Accept_Failed: + case ASSUAN_Invalid_Command: + case ASSUAN_Unknown_Command: + case ASSUAN_Syntax_Error: + case ASSUAN_Parameter_Error: + case ASSUAN_Parameter_Conflict: + case ASSUAN_No_Input: + case ASSUAN_No_Output: + case ASSUAN_No_Data_Available: + case ASSUAN_Too_Much_Data: + case ASSUAN_Inquire_Unknown: + case ASSUAN_Inquire_Error: + case ASSUAN_Invalid_Option: + case ASSUAN_Unexpected_Status: + case ASSUAN_Unexpected_Data: + case ASSUAN_Invalid_Status: + return gpg_error (GPG_ERR_ASSUAN); + + case ASSUAN_Invalid_Response: + return gpg_error (GPG_ERR_INV_RESPONSE); + + case ASSUAN_Not_Implemented: + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + case ASSUAN_Line_Too_Long: + return gpg_error (GPG_ERR_LINE_TOO_LONG); + case ASSUAN_Line_Not_Terminated: + return gpg_error (GPG_ERR_INCOMPLETE_LINE); + case ASSUAN_Canceled: + return gpg_error (GPG_ERR_CANCELED); + + case ASSUAN_Unsupported_Algorithm: + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + case ASSUAN_Server_Resource_Problem: + return gpg_error (GPG_ERR_RESOURCE_LIMIT); + case ASSUAN_Server_IO_Error: + return gpg_error (GPG_ERR_GENERAL); + case ASSUAN_Server_Bug: + return gpg_error (GPG_ERR_BUG); + case ASSUAN_Invalid_Data: + return gpg_error (GPG_ERR_INV_DATA); + case ASSUAN_Invalid_Index: + return gpg_error (GPG_ERR_INV_INDEX); + case ASSUAN_Not_Confirmed: + return gpg_error (GPG_ERR_NOT_CONFIRMED); + case ASSUAN_Bad_Certificate: + return gpg_error (GPG_ERR_BAD_CERT); + case ASSUAN_Bad_Certificate_Chain: + return gpg_error (GPG_ERR_BAD_CERT_CHAIN); + case ASSUAN_Missing_Certificate: + return gpg_error (GPG_ERR_MISSING_CERT); + case ASSUAN_Bad_Signature: + return gpg_error (GPG_ERR_BAD_SIGNATURE); + case ASSUAN_No_Agent: + return gpg_error (GPG_ERR_NO_AGENT); + case ASSUAN_Agent_Error: + return gpg_error (GPG_ERR_AGENT); + case ASSUAN_No_Public_Key: + return gpg_error (GPG_ERR_NO_PUBKEY); + case ASSUAN_No_Secret_Key: + return gpg_error (GPG_ERR_NO_SECKEY); + case ASSUAN_Invalid_Name: + return gpg_error (GPG_ERR_INV_NAME); + + case ASSUAN_Cert_Revoked: + return gpg_error (GPG_ERR_CERT_REVOKED); + case ASSUAN_No_CRL_For_Cert: + return gpg_error (GPG_ERR_NO_CRL_KNOWN); + case ASSUAN_CRL_Too_Old: + return gpg_error (GPG_ERR_CRL_TOO_OLD); + case ASSUAN_Not_Trusted: + return gpg_error (GPG_ERR_NOT_TRUSTED); + + case ASSUAN_Card_Error: + return gpg_error (GPG_ERR_CARD); + case ASSUAN_Invalid_Card: + return gpg_error (GPG_ERR_INV_CARD); + case ASSUAN_No_PKCS15_App: + return gpg_error (GPG_ERR_NO_PKCS15_APP); + case ASSUAN_Card_Not_Present: + return gpg_error (GPG_ERR_CARD_NOT_PRESENT); + case ASSUAN_Invalid_Id: + return gpg_error (GPG_ERR_INV_ID); + default: + return gpg_error (GPG_ERR_GENERAL); + } +} + + +static gpgme_error_t +gpgsm_cancel (void *engine) +{ + engine_gpgsm_t gpgsm = engine; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + + if (gpgsm->status_cb.fd != -1) + _gpgme_io_close (gpgsm->status_cb.fd); + if (gpgsm->input_cb.fd != -1) + _gpgme_io_close (gpgsm->input_cb.fd); + if (gpgsm->output_cb.fd != -1) + _gpgme_io_close (gpgsm->output_cb.fd); + if (gpgsm->message_cb.fd != -1) + _gpgme_io_close (gpgsm->message_cb.fd); + + if (gpgsm->assuan_ctx) + { + assuan_disconnect (gpgsm->assuan_ctx); + gpgsm->assuan_ctx = NULL; + } + + return 0; +} + + +static void +gpgsm_release (void *engine) +{ + engine_gpgsm_t gpgsm = engine; + + if (!gpgsm) + return; + + gpgsm_cancel (engine); + + free (gpgsm->colon.attic.line); + free (gpgsm); +} + + +static gpgme_error_t +gpgsm_new (void **engine, const char *file_name, const char *home_dir) +{ + gpgme_error_t err = 0; + engine_gpgsm_t gpgsm; + const char *argv[5]; + int argc; +#if !USE_DESCRIPTOR_PASSING + int fds[2]; + int child_fds[4]; +#endif + char *dft_display = NULL; + char dft_ttyname[64]; + char *dft_ttytype = NULL; + char *optstr; + + gpgsm = calloc (1, sizeof *gpgsm); + if (!gpgsm) + return gpg_error_from_errno (errno); + + gpgsm->status_cb.fd = -1; + gpgsm->status_cb.dir = 1; + gpgsm->status_cb.tag = 0; + gpgsm->status_cb.data = gpgsm; + + gpgsm->input_cb.fd = -1; + gpgsm->input_cb.dir = 0; + gpgsm->input_cb.tag = 0; + gpgsm->input_cb.server_fd = -1; + gpgsm->output_cb.fd = -1; + gpgsm->output_cb.dir = 1; + gpgsm->output_cb.tag = 0; + gpgsm->output_cb.server_fd = -1; + gpgsm->message_cb.fd = -1; + gpgsm->message_cb.dir = 0; + gpgsm->message_cb.tag = 0; + gpgsm->message_cb.server_fd = -1; + + gpgsm->status.fnc = 0; + gpgsm->colon.fnc = 0; + gpgsm->colon.attic.line = 0; + gpgsm->colon.attic.linesize = 0; + gpgsm->colon.attic.linelen = 0; + gpgsm->colon.any = 0; + + gpgsm->io_cbs.add = NULL; + gpgsm->io_cbs.add_priv = NULL; + gpgsm->io_cbs.remove = NULL; + gpgsm->io_cbs.event = NULL; + gpgsm->io_cbs.event_priv = NULL; + +#if !USE_DESCRIPTOR_PASSING + if (_gpgme_io_pipe (fds, 0) < 0) + { + err = gpg_error_from_errno (errno); + goto leave; + } + gpgsm->input_cb.fd = fds[1]; + gpgsm->input_cb.server_fd = fds[0]; + + if (_gpgme_io_pipe (fds, 1) < 0) + { + err = gpg_error_from_errno (errno); + goto leave; + } + gpgsm->output_cb.fd = fds[0]; + gpgsm->output_cb.server_fd = fds[1]; + + if (_gpgme_io_pipe (fds, 0) < 0) + { + err = gpg_error_from_errno (errno); + goto leave; + } + gpgsm->message_cb.fd = fds[1]; + gpgsm->message_cb.server_fd = fds[0]; + + child_fds[0] = gpgsm->input_cb.server_fd; + child_fds[1] = gpgsm->output_cb.server_fd; + child_fds[2] = gpgsm->message_cb.server_fd; + child_fds[3] = -1; +#endif + + argc = 0; + argv[argc++] = "gpgsm"; + if (home_dir) + { + argv[argc++] = "--homedir"; + argv[argc++] = home_dir; + } + argv[argc++] = "--server"; + argv[argc++] = NULL; + +#if USE_DESCRIPTOR_PASSING + err = assuan_pipe_connect_ext + (&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (), + argv, NULL, NULL, NULL, 1); +#else + err = assuan_pipe_connect + (&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (), + argv, child_fds); +#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 (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (err) + { + err = map_assuan_error (err); + goto leave; + } + } + + if (isatty (1)) + { + if (ttyname_r (1, dft_ttyname, sizeof (dft_ttyname))) + { + err = gpg_error_from_errno (errno); + goto leave; + } + else + { + if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) + { + err = gpg_error_from_errno (errno); + goto leave; + } + err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL, + NULL, NULL, NULL); + free (optstr); + if (err) + { + err = map_assuan_error (err); + goto leave; + } + + err = _gpgme_getenv ("TERM", &dft_ttytype); + if (err) + goto leave; + if (dft_ttytype) + { + if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0) + { + free (dft_ttytype); + err = gpg_error_from_errno (errno); + goto leave; + } + free (dft_ttytype); + + err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + if (err) + { + err = map_assuan_error (err); + goto leave; + } + } + } + } + +#if !USE_DESCRIPTOR_PASSING + if (!err + && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd, + close_notify_handler, gpgsm) + || _gpgme_io_set_close_notify (gpgsm->output_cb.fd, + close_notify_handler, gpgsm) + || _gpgme_io_set_close_notify (gpgsm->message_cb.fd, + close_notify_handler, gpgsm))) + { + err = gpg_error (GPG_ERR_GENERAL); + goto leave; + } +#endif + + leave: + /* Close the server ends of the pipes. Our ends are closed in + gpgsm_release(). */ +#if !USE_DESCRIPTOR_PASSING + if (gpgsm->input_cb.server_fd != -1) + _gpgme_io_close (gpgsm->input_cb.server_fd); + if (gpgsm->output_cb.server_fd != -1) + _gpgme_io_close (gpgsm->output_cb.server_fd); + if (gpgsm->message_cb.server_fd != -1) + _gpgme_io_close (gpgsm->message_cb.server_fd); +#endif + + if (err) + gpgsm_release (gpgsm); + else + *engine = gpgsm; + + return err; +} + + +static gpgme_error_t +gpgsm_set_locale (void *engine, int category, const char *value) +{ + engine_gpgsm_t gpgsm = 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. GPGSM needs support + for this. */ + if (category == LC_CTYPE) + { + catstr = "lc-ctype"; + if (!value && gpgsm->lc_ctype_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + gpgsm->lc_ctype_set = 1; + } +#ifdef LC_MESSAGES + else if (category == LC_MESSAGES) + { + catstr = "lc-messages"; + if (!value && gpgsm->lc_messages_set) + return gpg_error (GPG_ERR_INV_VALUE); + if (value) + gpgsm->lc_messages_set = 1; + } +#endif /* LC_MESSAGES */ + else + return gpg_error (GPG_ERR_INV_VALUE); + + if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0) + err = gpg_error_from_errno (errno); + else + { + err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, + NULL, NULL, NULL, NULL); + free (optstr); + if (err) + err = map_assuan_error (err); + } + return err; +} + + +/* Forward declaration. */ +static gpgme_status_code_t parse_status (const char *name); + +static gpgme_error_t +gpgsm_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 map_assuan_error (err); + + do + { + err = assuan_read_line (ctx, &line, &linelen); + if (err) + return map_assuan_error (err); + + if (*line == '#' || !linelen) + continue; + + if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + return 0; + else if (linelen >= 4 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && line[3] == ' ') + err = map_assuan_error (atoi (&line[4])); + else if (linelen >= 2 + && line[0] == 'S' && line[1] == ' ') + { + char *rest; + gpgme_status_code_t r; + + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; + + r = parse_status (line + 2); + + if (r >= 0 && status_fnc) + err = status_fnc (status_fnc_value, r, rest); + else + err = gpg_error (GPG_ERR_GENERAL); + } + else + err = gpg_error (GPG_ERR_GENERAL); + } + while (!err); + + return err; +} + + +typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t; + +static void +gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type) +{ +#if !USE_DESCRIPTOR_PASSING + switch (fd_type) + { + case INPUT_FD: + _gpgme_io_close (gpgsm->input_cb.fd); + break; + case OUTPUT_FD: + _gpgme_io_close (gpgsm->output_cb.fd); + break; + case MESSAGE_FD: + _gpgme_io_close (gpgsm->message_cb.fd); + break; + } +#endif +} + +#define COMMANDLINELEN 40 +static gpgme_error_t +gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt) +{ + gpg_error_t err = 0; + char line[COMMANDLINELEN]; + char *which; + iocb_data_t *iocb_data; + int dir; + int fd; + + switch (fd_type) + { + case INPUT_FD: + which = "INPUT"; + iocb_data = &gpgsm->input_cb; + break; + + case OUTPUT_FD: + which = "OUTPUT"; + iocb_data = &gpgsm->output_cb; + break; + + case MESSAGE_FD: + which = "MESSAGE"; + iocb_data = &gpgsm->message_cb; + break; + + default: + return gpg_error (GPG_ERR_INV_VALUE); + } + + dir = iocb_data->dir; + +#if USE_DESCRIPTOR_PASSING + /* We try to short-cut the communication by giving GPGSM direct + access to the file descriptor, rather than using a pipe. */ + iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data); + if (iocb_data->server_fd < 0) + { + int fds[2]; + + if (_gpgme_io_pipe (fds, 0) < 0) + return gpg_error_from_errno (errno); + + iocb_data->fd = dir ? fds[0] : fds[1]; + iocb_data->server_fd = dir ? fds[1] : fds[0]; + + if (_gpgme_io_set_close_notify (iocb_data->fd, + close_notify_handler, gpgsm)) + { + err = gpg_error (GPG_ERR_GENERAL); + goto leave_set_fd; + } + } +#endif + + fd = iocb_data->server_fd; + +#if USE_DESCRIPTOR_PASSING + err = assuan_sendfd (gpgsm->assuan_ctx, fd); + if (err) + goto leave_set_fd; + + _gpgme_io_close (fd); + + if (opt) + snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt); + else + snprintf (line, COMMANDLINELEN, "%s FD", which); +#else + if (opt) + snprintf (line, COMMANDLINELEN, "%s FD=%i %s", which, fd, opt); + else + snprintf (line, COMMANDLINELEN, "%s FD=%i", which, fd); +#endif + + err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + +#if USE_DESCRIPTOR_PASSING + leave_set_fd: + if (err) + { + _gpgme_io_close (iocb_data->fd); + _gpgme_io_close (iocb_data->server_fd); + iocb_data->fd = -1; + iocb_data->server_fd = -1; + } +#endif + + return err; +} + + +static const char * +map_input_enc (gpgme_data_t d) +{ + switch (gpgme_data_get_encoding (d)) + { + case GPGME_DATA_ENCODING_NONE: + break; + case GPGME_DATA_ENCODING_BINARY: + return "--binary"; + case GPGME_DATA_ENCODING_BASE64: + return "--base64"; + case GPGME_DATA_ENCODING_ARMOR: + return "--armor"; + default: + break; + } + return NULL; +} + + +static int +status_cmp (const void *ap, const void *bp) +{ + const struct status_table_s *a = ap; + const struct status_table_s *b = bp; + + return strcmp (a->name, b->name); +} + + +static gpgme_status_code_t +parse_status (const char *name) +{ + struct status_table_s t, *r; + t.name = name; + r = bsearch (&t, status_table, DIM(status_table) - 1, + sizeof t, status_cmp); + return r ? r->code : -1; +} + + +static gpgme_error_t +status_handler (void *opaque, int fd) +{ + gpg_error_t assuan_err; + gpgme_error_t err = 0; + engine_gpgsm_t gpgsm = opaque; + char *line; + size_t linelen; + + do + { + assuan_err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen); + if (assuan_err) + { + /* Try our best to terminate the connection friendly. */ + /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */ + err = map_assuan_error (assuan_err); + DEBUG3 ("fd %d: error from assuan (%d) getting status line : %s \n", + fd, assuan_err, gpg_strerror (err)); + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + if (line[3] == ' ') + err = map_assuan_error (atoi (&line[4])); + else + err = gpg_error (GPG_ERR_GENERAL); + DEBUG2 ("fd %d: ERR line - mapped to: %s\n", + fd, err? gpg_strerror (err):"ok"); + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + if (gpgsm->status.fnc) + err = gpgsm->status.fnc (gpgsm->status.fnc_value, + GPGME_STATUS_EOF, ""); + + if (!err && gpgsm->colon.fnc && gpgsm->colon.any ) + { + /* We must tell a colon function about the EOF. We do + this only when we have seen any data lines. Note + that this inlined use of colon data lines will + eventually be changed into using a regular data + channel. */ + gpgsm->colon.any = 0; + err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL); + } + _gpgme_io_close (gpgsm->status_cb.fd); + DEBUG2 ("fd %d: OK line - final status: %s\n", + fd, err? gpg_strerror (err):"ok"); + return err; + } + else if (linelen > 2 + && line[0] == 'D' && line[1] == ' ' + && gpgsm->colon.fnc) + { + /* We are using the colon handler even for plain inline data + - strange name for that function but for historic reasons + we keep it. */ + /* FIXME We can't use this for binary data because we + assume this is a string. For the current usage of colon + output it is correct. */ + char *src = line + 2; + char *end = line + linelen; + char *dst; + char **aline = &gpgsm->colon.attic.line; + int *alinelen = &gpgsm->colon.attic.linelen; + + if (gpgsm->colon.attic.linesize + < *alinelen + linelen + 1) + { + char *newline = realloc (*aline, *alinelen + linelen + 1); + if (!newline) + err = gpg_error_from_errno (errno); + else + { + *aline = newline; + gpgsm->colon.attic.linesize += linelen + 1; + } + } + if (!err) + { + dst = *aline + *alinelen; + + while (!err && src < end) + { + if (*src == '%' && src + 2 < end) + { + /* Handle escaped characters. */ + ++src; + *dst = _gpgme_hextobyte (src); + (*alinelen)++; + src += 2; + } + else + { + *dst = *src++; + (*alinelen)++; + } + + if (*dst == '\n') + { + /* Terminate the pending line, pass it to the colon + handler and reset it. */ + + gpgsm->colon.any = 1; + if (*alinelen > 1 && *(dst - 1) == '\r') + dst--; + *dst = '\0'; + + /* FIXME How should we handle the return code? */ + err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline); + if (!err) + { + dst = *aline; + *alinelen = 0; + } + } + else + dst++; + } + } + DEBUG2 ("fd %d: D line; final status: %s\n", + fd, err? gpg_strerror (err):"ok"); + } + else if (linelen > 2 + && line[0] == 'S' && line[1] == ' ') + { + char *rest; + gpgme_status_code_t r; + + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; + + r = parse_status (line + 2); + + if (r >= 0) + { + if (gpgsm->status.fnc) + err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest); + } + else + fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest); + DEBUG3 ("fd %d: S line (%s) - final status: %s\n", + fd, line+2, err? gpg_strerror (err):"ok"); + } + } + while (!err && assuan_pending_line (gpgsm->assuan_ctx)); + + return err; +} + + +static gpgme_error_t +add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler) +{ + gpgme_error_t err; + + err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv, + iocbd->fd, iocbd->dir, + handler, iocbd->data, &iocbd->tag); + if (err) + return err; + if (!iocbd->dir) + /* FIXME Kludge around poll() problem. */ + err = _gpgme_io_set_nonblocking (iocbd->fd); + return err; +} + + +static gpgme_error_t +start (engine_gpgsm_t gpgsm, const char *command) +{ + gpgme_error_t err; + int fdlist[5]; + int nfds; + + /* We need to know the fd used by assuan for reads. We do this by + using the assumption that the first returned fd from + assuan_get_active_fds() is always this one. */ + nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */, + fdlist, DIM (fdlist)); + if (nfds < 1) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + + /* We duplicate the file descriptor, so we can close it without + disturbing assuan. Alternatively, we could special case + status_fd and register/unregister it manually as needed, but this + increases code duplication and is more complicated as we can not + use the close notifications etc. */ + gpgsm->status_cb.fd = dup (fdlist[0]); + if (gpgsm->status_cb.fd < 0) + return gpg_error_from_syserror (); + + if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd, + close_notify_handler, gpgsm)) + { + close (gpgsm->status_cb.fd); + gpgsm->status_cb.fd = -1; + return gpg_error (GPG_ERR_GENERAL); + } + + err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler); + if (!err && gpgsm->input_cb.fd != -1) + err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler); + if (!err && gpgsm->output_cb.fd != -1) + err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler); + if (!err && gpgsm->message_cb.fd != -1) + err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler); + + if (!err) + err = map_assuan_error (assuan_write_line (gpgsm->assuan_ctx, command)); + + if (!err) + (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, GPGME_EVENT_START, NULL); + + return err; +} + + +#if USE_DESCRIPTOR_PASSING +static gpgme_error_t +gpgsm_reset (void *engine) +{ + engine_gpgsm_t gpgsm = engine; + + /* We must send a reset because we need to reset the list of + signers. Note that RESET does not reset OPTION commands. */ + return gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL); +} +#endif + + +static gpgme_error_t +gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + + gpgsm->input_cb.data = ciph; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + gpgsm->output_cb.data = plain; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0); + if (err) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (engine, "DECRYPT"); + return err; +} + + +static gpgme_error_t +gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + char *fpr = key->subkeys ? key->subkeys->fpr : NULL; + char *linep = fpr; + char *line; + int length = 8; /* "DELKEYS " */ + + if (!fpr) + return gpg_error (GPG_ERR_INV_VALUE); + + while (*linep) + { + length++; + if (*linep == '%' || *linep == ' ' || *linep == '+') + length += 2; + linep++; + } + length++; + + line = malloc (length); + if (!line) + return gpg_error_from_errno (errno); + + strcpy (line, "DELKEYS "); + linep = &line[8]; + + while (*fpr) + { + switch (*fpr) + { + case '%': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '5'; + break; + case ' ': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '0'; + break; + case '+': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = 'B'; + break; + default: + *(linep++) = *fpr; + break; + } + fpr++; + } + *linep = '\0'; + + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, line); + free (line); + + return err; +} + + +static gpgme_error_t +set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[]) +{ + gpgme_error_t err = 0; + assuan_context_t ctx = gpgsm->assuan_ctx; + char *line; + int linelen; + int invalid_recipients = 0; + int i = 0; + + linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */ + line = malloc (10 + 40 + 1); + if (!line) + return gpg_error_from_errno (errno); + strcpy (line, "RECIPIENT "); + while (!err && recp[i]) + { + char *fpr; + int newlen; + + if (!recp[i]->subkeys || !recp[i]->subkeys->fpr) + { + invalid_recipients++; + continue; + } + fpr = recp[i]->subkeys->fpr; + + newlen = 11 + strlen (fpr); + if (linelen < newlen) + { + char *newline = realloc (line, newlen); + if (! newline) + { + int saved_errno = errno; + free (line); + return gpg_error_from_errno (saved_errno); + } + line = newline; + linelen = newlen; + } + strcpy (&line[10], fpr); + + err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc, + gpgsm->status.fnc_value); + /* FIXME: This requires more work. */ + if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY) + invalid_recipients++; + else if (err) + { + free (line); + return err; + } + i++; + } + free (line); + return gpg_error (invalid_recipients + ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR); +} + + +static gpgme_error_t +gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, int use_armor) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + if (!recp) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + gpgsm->input_cb.data = plain; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return err; + gpgsm->output_cb.data = ciph; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); + if (err) + return err; + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = set_recipients (gpgsm, recp); + + if (!err) + err = start (gpgsm, "ENCRYPT"); + + return err; +} + + +static gpgme_error_t +gpgsm_export (void *engine, const char *pattern, unsigned int reserved, + gpgme_data_t keydata, int use_armor) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err = 0; + char *cmd; + + if (!gpgsm || reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!pattern) + pattern = ""; + + cmd = malloc (7 + strlen (pattern) + 1); + if (!cmd) + return gpg_error_from_errno (errno); + strcpy (cmd, "EXPORT "); + strcpy (&cmd[7], pattern); + + gpgsm->output_cb.data = keydata; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); + if (err) + return err; + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, cmd); + free (cmd); + return err; +} + + +static gpgme_error_t +gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved, + gpgme_data_t keydata, int use_armor) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err = 0; + char *line; + /* Length is "EXPORT " + p + '\0'. */ + int length = 7 + 1; + char *linep; + + if (!gpgsm || reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + if (pattern && *pattern) + { + const char **pat = pattern; + + while (*pat) + { + const char *patlet = *pat; + + while (*patlet) + { + length++; + if (*patlet == '%' || *patlet == ' ' || *patlet == '+') + length += 2; + patlet++; + } + pat++; + length++; + } + } + line = malloc (length); + if (!line) + return gpg_error_from_errno (errno); + + strcpy (line, "EXPORT "); + linep = &line[7]; + + if (pattern && *pattern) + { + while (*pattern) + { + const char *patlet = *pattern; + + while (*patlet) + { + switch (*patlet) + { + case '%': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '5'; + break; + case ' ': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '0'; + break; + case '+': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = 'B'; + break; + default: + *(linep++) = *patlet; + break; + } + patlet++; + } + pattern++; + if (*pattern) + *linep++ = ' '; + } + } + *linep = '\0'; + + gpgsm->output_cb.data = keydata; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); + if (err) + return err; + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, line); + free (line); + return err; +} + + +static gpgme_error_t +gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor, + gpgme_data_t pubkey, gpgme_data_t seckey) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + + if (!gpgsm || !pubkey || seckey) + return gpg_error (GPG_ERR_INV_VALUE); + + gpgsm->input_cb.data = help_data; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return err; + gpgsm->output_cb.data = pubkey; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); + if (err) + return err; + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, "GENKEY"); + return err; +} + + +static gpgme_error_t +gpgsm_import (void *engine, gpgme_data_t keydata) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + + gpgsm->input_cb.data = keydata; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return err; + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, "IMPORT"); + return err; +} + + +static gpgme_error_t +gpgsm_keylist (void *engine, const char *pattern, int secret_only, + gpgme_keylist_mode_t mode) +{ + engine_gpgsm_t gpgsm = engine; + char *line; + gpgme_error_t err; + int list_mode = 0; + + if (mode & GPGME_KEYLIST_MODE_LOCAL) + list_mode |= 1; + if (mode & GPGME_KEYLIST_MODE_EXTERN) + list_mode |= 2; + + if (!pattern) + pattern = ""; + + /* Always send list-mode option because RESET does not reset it. */ + if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) + return gpg_error_from_errno (errno); + err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + free (line); + if (err) + return err; + + + /* Always send key validation because RESET does not reset it. */ + + /* Use the validation mode if required. We don't check for an error + yet because this is a pretty fresh gpgsm features. */ + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (mode & GPGME_KEYLIST_MODE_VALIDATE)? + "OPTION with-validation=1": + "OPTION with-validation=0" , + NULL, NULL); + + + /* Length is "LISTSECRETKEYS " + p + '\0'. */ + line = malloc (15 + strlen (pattern) + 1); + if (!line) + return gpg_error_from_errno (errno); + if (secret_only) + { + strcpy (line, "LISTSECRETKEYS "); + strcpy (&line[15], pattern); + } + else + { + strcpy (line, "LISTKEYS "); + strcpy (&line[9], pattern); + } + + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, line); + free (line); + return err; +} + + +static gpgme_error_t +gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, + int reserved, gpgme_keylist_mode_t mode) +{ + engine_gpgsm_t gpgsm = engine; + char *line; + gpgme_error_t err; + /* Length is "LISTSECRETKEYS " + p + '\0'. */ + int length = 15 + 1; + char *linep; + int any_pattern = 0; + int list_mode = 0; + + if (reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + if (mode & GPGME_KEYLIST_MODE_LOCAL) + list_mode |= 1; + if (mode & GPGME_KEYLIST_MODE_EXTERN) + list_mode |= 2; + + /* Always send list-mode option because RESET does not reset it. */ + if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) + return gpg_error_from_errno (errno); + err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); + free (line); + if (err) + return err; + + /* Always send key validation because RESET does not reset it. */ + /* Use the validation mode if required. We don't check for an error + yet because this is a pretty fresh gpgsm features. */ + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (mode & GPGME_KEYLIST_MODE_VALIDATE)? + "OPTION with-validation=1": + "OPTION with-validation=0" , + NULL, NULL); + + + if (pattern && *pattern) + { + const char **pat = pattern; + + while (*pat) + { + const char *patlet = *pat; + + while (*patlet) + { + length++; + if (*patlet == '%' || *patlet == ' ' || *patlet == '+') + length += 2; + patlet++; + } + pat++; + length++; + } + } + line = malloc (length); + if (!line) + return gpg_error_from_errno (errno); + if (secret_only) + { + strcpy (line, "LISTSECRETKEYS "); + linep = &line[15]; + } + else + { + strcpy (line, "LISTKEYS "); + linep = &line[9]; + } + + if (pattern && *pattern) + { + while (*pattern) + { + const char *patlet = *pattern; + + while (*patlet) + { + switch (*patlet) + { + case '%': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '5'; + break; + case ' ': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = '0'; + break; + case '+': + *(linep++) = '%'; + *(linep++) = '2'; + *(linep++) = 'B'; + break; + default: + *(linep++) = *patlet; + break; + } + patlet++; + } + any_pattern = 1; + *linep++ = ' '; + pattern++; + } + } + if (any_pattern) + linep--; + *linep = '\0'; + + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, line); + free (line); + return err; +} + + +static gpgme_error_t +gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, + gpgme_sig_mode_t mode, int use_armor, int use_textmode, + int include_certs, gpgme_ctx_t ctx /* FIXME */) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + char *assuan_cmd; + int i; + gpgme_key_t key; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + + /* FIXME: This does not work as RESET does not reset it so we can't + revert back to default. */ + if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT) + { + /* FIXME: Make sure that if we run multiple operations, that we + can reset any previously set value in case the default is + requested. */ + + if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0) + return gpg_error_from_errno (errno); + err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd, + NULL, NULL); + free (assuan_cmd); + if (err) + return err; + } + + for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++) + { + const char *s = key->subkeys ? key->subkeys->fpr : NULL; + if (s && strlen (s) < 80) + { + char buf[100]; + + strcpy (stpcpy (buf, "SIGNER "), s); + err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf, + NULL, NULL); + } + else + err = gpg_error (GPG_ERR_INV_VALUE); + gpgme_key_unref (key); + if (err) + return err; + } + + gpgsm->input_cb.data = in; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return err; + gpgsm->output_cb.data = out; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" : 0); + if (err) + return err; + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + + err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH + ? "SIGN --detached" : "SIGN"); + return err; +} + + +static gpgme_error_t +gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, + gpgme_data_t plaintext) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + + if (!gpgsm) + return gpg_error (GPG_ERR_INV_VALUE); + + gpgsm->input_cb.data = sig; + err = gpgsm_set_fd (gpgsm, INPUT_FD, map_input_enc (gpgsm->input_cb.data)); + if (err) + return err; + if (plaintext) + { + /* Normal or cleartext signature. */ + gpgsm->output_cb.data = plaintext; + err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + } + else + { + /* Detached signature. */ + gpgsm->message_cb.data = signed_text; + err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0); + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + } + + if (!err) + err = start (gpgsm, "VERIFY"); + + return err; +} + + +static void +gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc, + void *fnc_value) +{ + engine_gpgsm_t gpgsm = engine; + + gpgsm->status.fnc = fnc; + gpgsm->status.fnc_value = fnc_value; +} + + +static gpgme_error_t +gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc, + void *fnc_value) +{ + engine_gpgsm_t gpgsm = engine; + + gpgsm->colon.fnc = fnc; + gpgsm->colon.fnc_value = fnc_value; + gpgsm->colon.any = 0; + return 0; +} + + +static void +gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs) +{ + engine_gpgsm_t gpgsm = engine; + gpgsm->io_cbs = *io_cbs; +} + + +static void +gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data) +{ + engine_gpgsm_t gpgsm = engine; + + if (gpgsm->io_cbs.event) + (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data); +} + + +struct engine_ops _gpgme_engine_ops_gpgsm = + { + /* Static functions. */ + _gpgme_get_gpgsm_path, + gpgsm_get_version, + gpgsm_get_req_version, + gpgsm_new, + + /* Member functions. */ + gpgsm_release, +#if USE_DESCRIPTOR_PASSING + gpgsm_reset, +#else + NULL, /* reset */ +#endif + gpgsm_set_status_handler, + NULL, /* set_command_handler */ + gpgsm_set_colon_line_handler, + gpgsm_set_locale, + gpgsm_decrypt, + gpgsm_delete, + NULL, /* edit */ + gpgsm_encrypt, + NULL, /* encrypt_sign */ + gpgsm_export, + gpgsm_export_ext, + gpgsm_genkey, + gpgsm_import, + gpgsm_keylist, + gpgsm_keylist_ext, + gpgsm_sign, + NULL, /* trustlist */ + gpgsm_verify, + gpgsm_set_io_cbs, + gpgsm_io_event, + gpgsm_cancel + }; + +#endif /*!HAVE_W32_SYSTEM*/ diff --git a/libkdenetwork/libgpgme-copy/gpgme/engine.c b/libkdenetwork/libgpgme-copy/gpgme/engine.c new file mode 100644 index 000000000..a64b4625d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/engine.c @@ -0,0 +1,744 @@ +/* engine.c - GPGME engine support. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2006 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 <string.h> +#include <errno.h> +#include <assert.h> + +#include "gpgme.h" +#include "util.h" +#include "sema.h" +#include "ops.h" + +#include "engine.h" +#include "engine-backend.h" + + +struct engine +{ + struct engine_ops *ops; + void *engine; +}; + + +static struct engine_ops *engine_ops[] = + { + &_gpgme_engine_ops_gpg, /* OpenPGP. */ +#ifdef ENABLE_GPGSM + &_gpgme_engine_ops_gpgsm /* CMS. */ +#else + NULL +#endif + }; + + +/* The engine info. */ +static gpgme_engine_info_t engine_info; +DEFINE_STATIC_LOCK (engine_info_lock); + + +/* Get the file name of the engine for PROTOCOL. */ +static const char * +engine_get_file_name (gpgme_protocol_t proto) +{ + if (proto > DIM (engine_ops)) + return NULL; + + if (engine_ops[proto] && engine_ops[proto]->get_file_name) + return (*engine_ops[proto]->get_file_name) (); + else + return NULL; +} + + +/* Get a malloced string containing the version number of the engine + for PROTOCOL. */ +static char * +engine_get_version (gpgme_protocol_t proto, const char *file_name) +{ + if (proto > DIM (engine_ops)) + return NULL; + + if (engine_ops[proto] && engine_ops[proto]->get_version) + return (*engine_ops[proto]->get_version) (file_name); + else + return NULL; +} + + +/* Get the required version number of the engine for PROTOCOL. */ +static const char * +engine_get_req_version (gpgme_protocol_t proto) +{ + if (proto > DIM (engine_ops)) + return NULL; + + if (engine_ops[proto] && engine_ops[proto]->get_req_version) + return (*engine_ops[proto]->get_req_version) (); + else + return NULL; +} + + +/* Verify the version requirement for the engine for PROTOCOL. */ +gpgme_error_t +gpgme_engine_check_version (gpgme_protocol_t proto) +{ + gpgme_error_t err; + gpgme_engine_info_t info; + int result; + + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + + LOCK (engine_info_lock); + } + + while (info && info->protocol != proto) + info = info->next; + + if (!info) + result = 0; + else + result = _gpgme_compare_versions (info->version, + info->req_version); + + UNLOCK (engine_info_lock); + return result ? 0 : gpg_error (GPG_ERR_INV_ENGINE); +} + + +/* Release the engine info INFO. */ +void +_gpgme_engine_info_release (gpgme_engine_info_t info) +{ + while (info) + { + gpgme_engine_info_t next_info = info->next; + + assert (info->file_name); + free (info->file_name); + if (info->home_dir) + free (info->home_dir); + if (info->version) + free (info->version); + free (info); + info = next_info; + } +} + + +/* Get the information about the configured and installed engines. A + pointer to the first engine in the statically allocated linked list + is returned in *INFO. If an error occurs, it is returned. The + returned data is valid until the next gpgme_set_engine_info. */ +gpgme_error_t +gpgme_get_engine_info (gpgme_engine_info_t *info) +{ + LOCK (engine_info_lock); + if (!engine_info) + { + gpgme_engine_info_t *lastp = &engine_info; + gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP, + GPGME_PROTOCOL_CMS }; + unsigned int proto; + + for (proto = 0; proto < DIM (proto_list); proto++) + { + const char *ofile_name = engine_get_file_name (proto_list[proto]); + char *file_name; + + if (!ofile_name) + continue; + + file_name = strdup (ofile_name); + + *lastp = malloc (sizeof (*engine_info)); + if (!*lastp || !file_name) + { + int saved_errno = errno; + + _gpgme_engine_info_release (engine_info); + engine_info = NULL; + + if (file_name) + free (file_name); + + UNLOCK (engine_info_lock); + return gpg_error_from_errno (saved_errno); + } + + (*lastp)->protocol = proto_list[proto]; + (*lastp)->file_name = file_name; + (*lastp)->home_dir = NULL; + (*lastp)->version = engine_get_version (proto_list[proto], NULL); + (*lastp)->req_version = engine_get_req_version (proto_list[proto]); + (*lastp)->next = NULL; + lastp = &(*lastp)->next; + } + } + + *info = engine_info; + UNLOCK (engine_info_lock); + return 0; +} + + +/* Get a deep copy of the engine info and return it in INFO. */ +gpgme_error_t +_gpgme_engine_info_copy (gpgme_engine_info_t *r_info) +{ + gpgme_error_t err = 0; + gpgme_engine_info_t info; + gpgme_engine_info_t new_info; + gpgme_engine_info_t *lastp; + + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + + LOCK (engine_info_lock); + } + + new_info = NULL; + lastp = &new_info; + + while (info) + { + char *file_name; + char *home_dir; + char *version; + + assert (info->file_name); + file_name = strdup (info->file_name); + + if (info->home_dir) + { + home_dir = strdup (info->home_dir); + if (!home_dir) + err = gpg_error_from_errno (errno); + } + else + home_dir = NULL; + + if (info->version) + { + version = strdup (info->version); + if (!version) + err = gpg_error_from_errno (errno); + } + else + version = NULL; + + *lastp = malloc (sizeof (*engine_info)); + if (!*lastp || !file_name || err) + { + int saved_errno = errno; + + _gpgme_engine_info_release (new_info); + + if (file_name) + free (file_name); + if (home_dir) + free (home_dir); + if (version) + free (version); + + UNLOCK (engine_info_lock); + return gpg_error_from_errno (saved_errno); + } + + (*lastp)->protocol = info->protocol; + (*lastp)->file_name = file_name; + (*lastp)->home_dir = home_dir; + (*lastp)->version = version; + (*lastp)->req_version = info->req_version; + (*lastp)->next = NULL; + lastp = &(*lastp)->next; + + info = info->next; + } + + *r_info = new_info; + UNLOCK (engine_info_lock); + return 0; +} + + +/* Set the engine info for the info list INFO, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +_gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + char *new_file_name; + char *new_home_dir; + + /* FIXME: Use some PROTO_MAX definition. */ + if (proto > DIM (engine_ops)) + return gpg_error (GPG_ERR_INV_VALUE); + + while (info && info->protocol != proto) + info = info->next; + + if (!info) + return gpg_error (GPG_ERR_INV_ENGINE); + + /* Prepare new members. */ + if (file_name) + new_file_name = strdup (file_name); + else + { + const char *ofile_name = engine_get_file_name (proto); + assert (ofile_name); + new_file_name = strdup (ofile_name); + } + if (!new_file_name) + return gpg_error_from_errno (errno); + + if (home_dir) + { + new_home_dir = strdup (home_dir); + if (!new_home_dir) + { + free (new_file_name); + return gpg_error_from_errno (errno); + } + } + else + new_home_dir = NULL; + + /* Remove the old members. */ + assert (info->file_name); + free (info->file_name); + if (info->home_dir) + free (info->home_dir); + if (info->version) + free (info->version); + + /* Install the new members. */ + info->file_name = new_file_name; + info->home_dir = new_home_dir; + info->version = engine_get_version (proto, new_file_name); + + return 0; +} + + +/* Set the default engine info for the protocol PROTO to the file name + FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +gpgme_set_engine_info (gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + gpgme_error_t err; + gpgme_engine_info_t info; + + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + + LOCK (engine_info_lock); + } + + err = _gpgme_set_engine_info (info, proto, file_name, home_dir); + UNLOCK (engine_info_lock); + return err; +} + + +gpgme_error_t +_gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine) +{ + engine_t engine; + + if (!info->file_name || !info->version) + return gpg_error (GPG_ERR_INV_ENGINE); + + engine = calloc (1, sizeof *engine); + if (!engine) + return gpg_error_from_errno (errno); + + engine->ops = engine_ops[info->protocol]; + if (engine->ops->new) + { + gpgme_error_t err; + err = (*engine->ops->new) (&engine->engine, + info->file_name, info->home_dir); + if (err) + { + free (engine); + return err; + } + } + else + engine->engine = NULL; + + *r_engine = engine; + return 0; +} + + +gpgme_error_t +_gpgme_engine_reset (engine_t engine) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->reset) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->reset) (engine->engine); +} + + +void +_gpgme_engine_release (engine_t engine) +{ + if (!engine) + return; + + if (engine->ops->release) + (*engine->ops->release) (engine->engine); + free (engine); +} + + +void +_gpgme_engine_set_status_handler (engine_t engine, + engine_status_handler_t fnc, void *fnc_value) +{ + if (!engine) + return; + + if (engine->ops->set_status_handler) + (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value); +} + + +gpgme_error_t +_gpgme_engine_set_command_handler (engine_t engine, + engine_command_handler_t fnc, + void *fnc_value, + gpgme_data_t linked_data) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->set_command_handler) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->set_command_handler) (engine->engine, + fnc, fnc_value, linked_data); +} + +gpgme_error_t +_gpgme_engine_set_colon_line_handler (engine_t engine, + engine_colon_line_handler_t fnc, + void *fnc_value) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->set_colon_line_handler) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->set_colon_line_handler) (engine->engine, + fnc, fnc_value); +} + +gpgme_error_t +_gpgme_engine_set_locale (engine_t engine, int category, + const char *value) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->set_locale) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->set_locale) (engine->engine, category, value); +} + +gpgme_error_t +_gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph, + gpgme_data_t plain) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->decrypt) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->decrypt) (engine->engine, ciph, plain); +} + +gpgme_error_t +_gpgme_engine_op_delete (engine_t engine, gpgme_key_t key, + int allow_secret) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->delete) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->delete) (engine->engine, key, allow_secret); +} + + +gpgme_error_t +_gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key, + gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->edit) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->edit) (engine->engine, type, key, out, ctx); +} + + +gpgme_error_t +_gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, int use_armor) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->encrypt) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph, + use_armor); +} + + +gpgme_error_t +_gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, + int use_armor, gpgme_ctx_t ctx /* FIXME */) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->encrypt_sign) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->encrypt_sign) (engine->engine, recp, flags, + plain, ciph, use_armor, ctx); +} + + +gpgme_error_t +_gpgme_engine_op_export (engine_t engine, const char *pattern, + unsigned int reserved, gpgme_data_t keydata, + int use_armor) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->export) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->export) (engine->engine, pattern, reserved, + keydata, use_armor); +} + + +gpgme_error_t +_gpgme_engine_op_export_ext (engine_t engine, const char *pattern[], + unsigned int reserved, gpgme_data_t keydata, + int use_armor) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->export_ext) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->export_ext) (engine->engine, pattern, reserved, + keydata, use_armor); +} + + +gpgme_error_t +_gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data, + int use_armor, gpgme_data_t pubkey, + gpgme_data_t seckey) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->genkey) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->genkey) (engine->engine, help_data, use_armor, + pubkey, seckey); +} + + +gpgme_error_t +_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->import) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->import) (engine->engine, keydata); +} + + +gpgme_error_t +_gpgme_engine_op_keylist (engine_t engine, const char *pattern, + int secret_only, gpgme_keylist_mode_t mode) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->keylist) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode); +} + + +gpgme_error_t +_gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], + int secret_only, int reserved, + gpgme_keylist_mode_t mode) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->keylist_ext) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only, + reserved, mode); +} + + +gpgme_error_t +_gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out, + gpgme_sig_mode_t mode, int use_armor, + int use_textmode, int include_certs, + gpgme_ctx_t ctx /* FIXME */) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->sign) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor, + use_textmode, include_certs, ctx); +} + + +gpgme_error_t +_gpgme_engine_op_trustlist (engine_t engine, const char *pattern) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->trustlist) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->trustlist) (engine->engine, pattern); +} + + +gpgme_error_t +_gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig, + gpgme_data_t signed_text, gpgme_data_t plaintext) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->verify) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext); +} + + +void +_gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs) +{ + if (!engine) + return; + + (*engine->ops->set_io_cbs) (engine->engine, io_cbs); +} + + +void +_gpgme_engine_io_event (engine_t engine, + gpgme_event_io_t type, void *type_data) +{ + if (!engine) + return; + + (*engine->ops->io_event) (engine->engine, type, type_data); +} + + +gpgme_error_t +_gpgme_engine_cancel (engine_t engine) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->cancel) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->cancel) (engine->engine); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/engine.h b/libkdenetwork/libgpgme-copy/gpgme/engine.h new file mode 100644 index 000000000..1fe24f553 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/engine.h @@ -0,0 +1,133 @@ +/* engine.h - GPGME engine interface. + 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. */ + +#ifndef ENGINE_H +#define ENGINE_H + +#include "gpgme.h" + +struct engine; +typedef struct engine *engine_t; + +typedef gpgme_error_t (*engine_status_handler_t) (void *priv, + gpgme_status_code_t code, + char *args); +typedef gpgme_error_t (*engine_colon_line_handler_t) (void *priv, char *line); +typedef gpgme_error_t (*engine_command_handler_t) (void *priv, + gpgme_status_code_t code, + const char *keyword, + int fd, int *processed); + +/* Get a deep copy of the engine info and return it in INFO. */ +gpgme_error_t _gpgme_engine_info_copy (gpgme_engine_info_t *r_info); + +/* Release the engine info INFO. */ +void _gpgme_engine_info_release (gpgme_engine_info_t info); + +/* Set the engine info for the info list INFO, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t _gpgme_set_engine_info (gpgme_engine_info_t info, + gpgme_protocol_t praoto, + const char *file_name, + const char *home_dir); + + +gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info, + engine_t *r_engine); +gpgme_error_t _gpgme_engine_reset (engine_t engine); + +gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category, + const char *value); + +void _gpgme_engine_release (engine_t engine); +void _gpgme_engine_set_status_handler (engine_t engine, + engine_status_handler_t fnc, + void *fnc_value); +gpgme_error_t _gpgme_engine_set_command_handler (engine_t engine, + engine_command_handler_t fnc, + void *fnc_value, + gpgme_data_t data); +gpgme_error_t +_gpgme_engine_set_colon_line_handler (engine_t engine, + engine_colon_line_handler_t fnc, + void *fnc_value); +gpgme_error_t _gpgme_engine_op_decrypt (engine_t engine, + gpgme_data_t ciph, + gpgme_data_t plain); +gpgme_error_t _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key, + int allow_secret); +gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type, + gpgme_key_t key, gpgme_data_t out, + gpgme_ctx_t ctx /* FIXME */); +gpgme_error_t _gpgme_engine_op_encrypt (engine_t engine, + gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t ciph, + int use_armor); +gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine, + gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t ciph, + int use_armor, + gpgme_ctx_t ctx /* FIXME */); +gpgme_error_t _gpgme_engine_op_export (engine_t engine, const char *pattern, + unsigned int reserved, + gpgme_data_t keydata, int use_armor); +gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine, + const char *pattern[], + unsigned int reserved, + gpgme_data_t keydata, + int use_armor); +gpgme_error_t _gpgme_engine_op_genkey (engine_t engine, + gpgme_data_t help_data, + int use_armor, gpgme_data_t pubkey, + gpgme_data_t seckey); +gpgme_error_t _gpgme_engine_op_import (engine_t engine, + gpgme_data_t keydata); +gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, + const char *pattern, + int secret_only, + gpgme_keylist_mode_t mode); +gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, + const char *pattern[], + int secret_only, + int reserved, + gpgme_keylist_mode_t mode); +gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, + gpgme_data_t out, gpgme_sig_mode_t mode, + int use_armor, int use_textmode, + int include_certs, + gpgme_ctx_t ctx /* FIXME */); +gpgme_error_t _gpgme_engine_op_trustlist (engine_t engine, + const char *pattern); +gpgme_error_t _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig, + gpgme_data_t signed_text, + gpgme_data_t plaintext); + +void _gpgme_engine_set_io_cbs (engine_t engine, + gpgme_io_cbs_t io_cbs); +void _gpgme_engine_io_event (engine_t engine, + gpgme_event_io_t type, void *type_data); + +gpgme_error_t _gpgme_engine_cancel (engine_t engine); + +#endif /* ENGINE_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/error.c b/libkdenetwork/libgpgme-copy/gpgme/error.c new file mode 100644 index 000000000..6f37ef7d3 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/error.c @@ -0,0 +1,92 @@ +/* error.c - Error handling for GPGME. + Copyright (C) 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 <gpgme.h> + +/* Return a pointer to a string containing a description of the error + code in the error value ERR. */ +const char * +gpgme_strerror (gpgme_error_t err) +{ + return gpg_strerror (err); +} + + +/* Return the error string for ERR in the user-supplied buffer BUF of + size BUFLEN. This function is, in contrast to gpg_strerror, + thread-safe if a thread-safe strerror_r() function is provided by + the system. If the function succeeds, 0 is returned and BUF + contains the string describing the error. If the buffer was not + large enough, ERANGE is returned and BUF contains as much of the + beginning of the error string as fits into the buffer. */ +int +gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen) +{ + return gpg_strerror_r (err, buf, buflen); +} + + +/* Return a pointer to a string containing a description of the error + source in the error value ERR. */ +const char * +gpgme_strsource (gpgme_error_t err) +{ + return gpg_strsource (err); +} + + +/* Retrieve the error code for the system error ERR. This returns + GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report + this). */ +gpgme_err_code_t +gpgme_err_code_from_errno (int err) +{ + return gpg_err_code_from_errno (err); +} + + +/* Retrieve the system error for the error code CODE. This returns 0 + if CODE is not a system error code. */ +int +gpgme_err_code_to_errno (gpgme_err_code_t code) +{ + return gpg_err_code_from_errno (code); +} + + +/* Return an error value with the error source SOURCE and the system + error ERR. */ +gpgme_error_t +gpgme_err_make_from_errno (gpg_err_source_t source, int err) +{ + return gpg_err_make_from_errno (source, err); +} + + +/* Return an error value with the system error ERR. */ +gpgme_err_code_t +gpgme_error_from_errno (int err) +{ + return gpgme_error (gpg_err_code_from_errno (err)); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/export.c b/libkdenetwork/libgpgme-copy/gpgme/export.c new file mode 100644 index 000000000..079a7e0e9 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/export.c @@ -0,0 +1,117 @@ +/* export.c - Export a key. + 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 "gpgme.h" +#include "context.h" +#include "ops.h" + + +static gpgme_error_t +export_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + return 0; +} + + +static gpgme_error_t +export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, + unsigned int reserved, gpgme_data_t keydata) +{ + gpgme_error_t err; + + if (!keydata) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); + + return _gpgme_engine_op_export (ctx->engine, pattern, reserved, keydata, + ctx->use_armor); +} + + +/* Export the keys listed in RECP into KEYDATA. */ +gpgme_error_t +gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, + unsigned int reserved, gpgme_data_t keydata) +{ + return export_start (ctx, 0, pattern, reserved, keydata); +} + + +/* Export the keys listed in RECP into KEYDATA. */ +gpgme_error_t +gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved, + gpgme_data_t keydata) +{ + gpgme_error_t err = export_start (ctx, 1, pattern, reserved, keydata); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +static gpgme_error_t +export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], + unsigned int reserved, gpgme_data_t keydata) +{ + gpgme_error_t err; + + if (!keydata) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); + + return _gpgme_engine_op_export_ext (ctx->engine, pattern, reserved, keydata, + ctx->use_armor); +} + + +/* Export the keys listed in RECP into KEYDATA. */ +gpgme_error_t +gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[], + unsigned int reserved, gpgme_data_t keydata) +{ + return export_ext_start (ctx, 0, pattern, reserved, keydata); +} + + +/* Export the keys listed in RECP into KEYDATA. */ +gpgme_error_t +gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], + unsigned int reserved, gpgme_data_t keydata) +{ + gpgme_error_t err = export_ext_start (ctx, 1, pattern, reserved, keydata); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/fakes.c b/libkdenetwork/libgpgme-copy/gpgme/fakes.c new file mode 100644 index 000000000..44d5940f1 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/fakes.c @@ -0,0 +1,24 @@ +#include <config.h> + +/** How can this work? The prototypes are not defined anywhere for code using those functions.... */ + +#ifndef HAVE_STPCPY +#include "stpcpy.c" +#endif + +/*#ifndef HAVE_ISASCII +#include "isascii.c" +#endif*/ + +#ifndef HAVE_PUTC_UNLOCKED +#ifndef __FreeBSD__ +#include "putc_unlocked.c" +#endif +#endif + +#ifndef HAVE_MEMRCHR +#include "memrchr.c" +#endif + + + diff --git a/libkdenetwork/libgpgme-copy/gpgme/funopen.c b/libkdenetwork/libgpgme-copy/gpgme/funopen.c new file mode 100644 index 000000000..55b32230d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/funopen.c @@ -0,0 +1,43 @@ +/* funopen.c - Replacement for funopen. + Copyright (C) 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 <stdio.h> + +#ifdef HAVE_FOPENCOOKIE +FILE * +funopen(const void *cookie, cookie_read_function_t *readfn, + cookie_write_function_t *writefn, + cookie_seek_function_t *seekfn, + cookie_close_function_t *closefn) +{ + cookie_io_functions_t io = { read: readfn, write: writefn, + seek: seekfn, close: closefn }; + + return fopencookie ((void *) cookie, + readfn ? (writefn ? "rw" : "r") + : (writefn ? "w" : ""), io); +} +#else +#error No known way to implement funopen. +#endif diff --git a/libkdenetwork/libgpgme-copy/gpgme/genkey.c b/libkdenetwork/libgpgme-copy/gpgme/genkey.c new file mode 100644 index 000000000..afebb7cb6 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/genkey.c @@ -0,0 +1,206 @@ +/* genkey.c - Key generation. + 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 "context.h" +#include "ops.h" + + +typedef struct +{ + struct _gpgme_op_genkey_result result; + + /* The key parameters passed to the crypto engine. */ + gpgme_data_t key_parameter; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + + if (opd->result.fpr) + free (opd->result.fpr); + if (opd->key_parameter) + gpgme_data_release (opd->key_parameter); +} + + +gpgme_genkey_result_t +gpgme_op_genkey_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +static gpgme_error_t +genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + /* Pipe the status code through the progress status handler. */ + err = _gpgme_progress_status_handler (ctx, code, args); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_KEY_CREATED: + if (args && *args) + { + if (*args == 'B' || *args == 'P') + opd->result.primary = 1; + if (*args == 'B' || *args == 'S') + opd->result.sub = 1; + if (args[1] == ' ') + { + if (opd->result.fpr) + free (opd->result.fpr); + opd->result.fpr = strdup (&args[2]); + if (!opd->result.fpr) + return gpg_error_from_errno (errno); + } + } + break; + + case GPGME_STATUS_EOF: + /* FIXME: Should return some more useful error value. */ + if (!opd->result.primary && !opd->result.sub) + return gpg_error (GPG_ERR_GENERAL); + break; + + default: + break; + } + return 0; +} + + +static gpgme_error_t +get_key_parameter (const char *parms, gpgme_data_t *key_parameter) +{ + const char *content; + const char *attrib; + const char *endtag; + + /* Extract the key parameter from the XML structure. */ + parms = strstr (parms, "<GnupgKeyParms "); + if (!parms) + return gpg_error (GPG_ERR_INV_VALUE); + + content = strchr (parms, '>'); + if (!content) + return gpg_error (GPG_ERR_INV_VALUE); + content++; + + attrib = strstr (parms, "format=\"internal\""); + if (!attrib || attrib >= content) + return gpg_error (GPG_ERR_INV_VALUE); + + endtag = strstr (content, "</GnupgKeyParms>"); + /* FIXME: Check that there are no control statements inside. */ + while (content[0] == '\n' + || (content[0] == '\r' && content[1] == '\n')) + content++; + + return gpgme_data_new_from_mem (key_parameter, content, + endtag - content, 1); +} + + +static gpgme_error_t +genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms, + gpgme_data_t pubkey, gpgme_data_t seckey) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + err = get_key_parameter (parms, &opd->key_parameter); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx); + + return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter, + ctx->use_armor, pubkey, seckey); +} + + +/* Generate a new keypair and add it to the keyring. PUBKEY and + SECKEY should be null for now. PARMS specifies what keys should be + generated. */ +gpgme_error_t +gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms, + gpgme_data_t pubkey, gpgme_data_t seckey) +{ + return genkey_start (ctx, 0, parms, pubkey, seckey); +} + + +/* Generate a new keypair and add it to the keyring. PUBKEY and + SECKEY should be null for now. PARMS specifies what keys should be + generated. */ +gpgme_error_t +gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, gpgme_data_t pubkey, + gpgme_data_t seckey) +{ + gpgme_error_t err; + + err = genkey_start (ctx, 1, parms, pubkey, seckey); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/get-env.c b/libkdenetwork/libgpgme-copy/gpgme/get-env.c new file mode 100644 index 000000000..bea8949c7 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/get-env.c @@ -0,0 +1,59 @@ +/* get_env.c - A getenv() replacement. + Copyright (C) 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 <string.h> + +#include "util.h" + + +#if defined(HAVE_THREAD_SAFE_GETENV) || !defined (HAVE_GETENV_R) +/* We prefer using getenv() if it is thread-safe. */ + +/* Retrieve the environment variable NAME and return a copy of it in a + malloc()'ed buffer in *VALUE. If the environment variable is not + set, return NULL in *VALUE. */ +gpgme_error_t +_gpgme_getenv (const char *name, char **value) +{ + char *env_value; + + env_value = getenv (name); + if (!env_value) + *value = NULL; + else + { + *value = strdup (env_value); + if (!*value) + return gpg_error_from_errno (errno); + } + return 0; +} + +#else + +/* FIXME: Implement this when we have the specification for it. */ +#error Use of getenv_r not implemented. + +#endif diff --git a/libkdenetwork/libgpgme-copy/gpgme/gpgme.c b/libkdenetwork/libgpgme-copy/gpgme/gpgme.c new file mode 100644 index 000000000..6604cb08d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/gpgme.c @@ -0,0 +1,582 @@ +/* gpgme.c - GnuPG Made Easy. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <locale.h> + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "wait.h" + + +/* The default locale. */ +DEFINE_STATIC_LOCK (def_lc_lock); +static char *def_lc_ctype; +static char *def_lc_messages; + + +/* Create a new context as an environment for GPGME crypto + operations. */ +gpgme_error_t +gpgme_new (gpgme_ctx_t *r_ctx) +{ + gpgme_ctx_t ctx; + + ctx = calloc (1, sizeof *ctx); + if (!ctx) + return gpg_error_from_errno (errno); + + _gpgme_engine_info_copy (&ctx->engine_info); + if (!ctx->engine_info) + { + free (ctx); + return gpg_error_from_errno (errno); + } + + ctx->keylist_mode = GPGME_KEYLIST_MODE_LOCAL; + ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT; + ctx->protocol = GPGME_PROTOCOL_OpenPGP; + _gpgme_fd_table_init (&ctx->fdt); + + LOCK (def_lc_lock); + if (def_lc_ctype) + { + ctx->lc_ctype = strdup (def_lc_ctype); + if (!ctx->lc_ctype) + { + UNLOCK (def_lc_lock); + _gpgme_engine_info_release (ctx->engine_info); + free (ctx); + return gpg_error_from_errno (errno); + } + } + else + def_lc_ctype = NULL; + + if (def_lc_messages) + { + ctx->lc_messages = strdup (def_lc_messages); + if (!ctx->lc_messages) + { + UNLOCK (def_lc_lock); + if (ctx->lc_ctype) + free (ctx->lc_ctype); + _gpgme_engine_info_release (ctx->engine_info); + free (ctx); + return gpg_error_from_errno (errno); + } + } + else + def_lc_messages = NULL; + UNLOCK (def_lc_lock); + + *r_ctx = ctx; + return 0; +} + + +/* Cancel a pending asynchronous operation. */ +gpgme_error_t +gpgme_cancel (gpgme_ctx_t ctx) +{ + gpgme_error_t err; + + err = _gpgme_engine_cancel (ctx->engine); + if (err) + return err; + + err = gpg_error (GPG_ERR_CANCELED); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + + return 0; +} + +/* Release all resources associated with the given context. */ +void +gpgme_release (gpgme_ctx_t ctx) +{ + _gpgme_engine_release (ctx->engine); + _gpgme_fd_table_deinit (&ctx->fdt); + _gpgme_release_result (ctx); + gpgme_signers_clear (ctx); + if (ctx->signers) + free (ctx->signers); + if (ctx->lc_ctype) + free (ctx->lc_ctype); + if (ctx->lc_messages) + free (ctx->lc_messages); + _gpgme_engine_info_release (ctx->engine_info); + free (ctx); +} + + +void +_gpgme_release_result (gpgme_ctx_t ctx) +{ + struct ctx_op_data *data = ctx->op_data; + + while (data) + { + struct ctx_op_data *next_data = data->next; + if (data->cleanup) + (*data->cleanup) (data->hook); + free (data); + data = next_data; + } + ctx->op_data = NULL; +} + + +gpgme_error_t +gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol) +{ + if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS) + return gpg_error (GPG_ERR_INV_VALUE); + + if (ctx->protocol != protocol) + { + /* Shut down the engine when switching protocols. */ + if (ctx->engine) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } + + ctx->protocol = protocol; + } + return 0; +} + + +gpgme_protocol_t +gpgme_get_protocol (gpgme_ctx_t ctx) +{ + return ctx->protocol; +} + + +const char * +gpgme_get_protocol_name (gpgme_protocol_t protocol) +{ + switch (protocol) + { + case GPGME_PROTOCOL_OpenPGP: + return "OpenPGP"; + + case GPGME_PROTOCOL_CMS: + return "CMS"; + + default: + return NULL; + } +} + +/* Enable or disable the use of an ascii armor for all output. */ +void +gpgme_set_armor (gpgme_ctx_t ctx, int yes) +{ + ctx->use_armor = yes; +} + + +/* Return the state of the armor flag. */ +int +gpgme_get_armor (gpgme_ctx_t ctx) +{ + return ctx->use_armor; +} + + +/* Enable or disable the use of the special textmode. Textmode is for + example used for the RFC2015 signatures; note that the updated RFC + 3156 mandates that the MUA does some preparations so that textmode + is not needed anymore. */ +void +gpgme_set_textmode (gpgme_ctx_t ctx, int yes) +{ + ctx->use_textmode = yes; +} + +/* Return the state of the textmode flag. */ +int +gpgme_get_textmode (gpgme_ctx_t ctx) +{ + return ctx->use_textmode; +} + + +/* Set the number of certifications to include in an S/MIME message. + The default is GPGME_INCLUDE_CERTS_DEFAULT. -1 means all certs, + and -2 means all certs except the root cert. */ +void +gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs) +{ + if (nr_of_certs == GPGME_INCLUDE_CERTS_DEFAULT) + ctx->include_certs = GPGME_INCLUDE_CERTS_DEFAULT; + else if (nr_of_certs < -2) + ctx->include_certs = -2; + else + ctx->include_certs = nr_of_certs; +} + + +/* Get the number of certifications to include in an S/MIME + message. */ +int +gpgme_get_include_certs (gpgme_ctx_t ctx) +{ + return ctx->include_certs; +} + + +/* This function changes the default behaviour of the keylisting + functions. MODE is a bitwise-OR of the GPGME_KEYLIST_* flags. The + default mode is GPGME_KEYLIST_MODE_LOCAL. */ +gpgme_error_t +gpgme_set_keylist_mode (gpgme_ctx_t ctx, gpgme_keylist_mode_t mode) +{ + ctx->keylist_mode = mode; + return 0; +} + +/* This function returns the default behaviour of the keylisting + functions. */ +gpgme_keylist_mode_t +gpgme_get_keylist_mode (gpgme_ctx_t ctx) +{ + return ctx->keylist_mode; +} + + +/* This function sets a callback function to be used to pass a + passphrase to gpg. */ +void +gpgme_set_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, + void *cb_value) +{ + ctx->passphrase_cb = cb; + ctx->passphrase_cb_value = cb_value; +} + + +/* This function returns the callback function to be used to pass a + passphrase to the crypto engine. */ +void +gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *r_cb, + void **r_cb_value) +{ + if (r_cb) + *r_cb = ctx->passphrase_cb; + if (r_cb_value) + *r_cb_value = ctx->passphrase_cb_value; +} + + +/* This function sets a callback function to be used as a progress + indicator. */ +void +gpgme_set_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t cb, void *cb_value) +{ + ctx->progress_cb = cb; + ctx->progress_cb_value = cb_value; +} + + +/* This function returns the callback function to be used as a + progress indicator. */ +void +gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb, + void **r_cb_value) +{ + if (r_cb) + *r_cb = ctx->progress_cb; + if (r_cb_value) + *r_cb_value = ctx->progress_cb_value; +} + + +/* Set the I/O callback functions for CTX to IO_CBS. */ +void +gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs) +{ + if (io_cbs) + ctx->io_cbs = *io_cbs; + else + { + ctx->io_cbs.add = NULL; + ctx->io_cbs.add_priv = NULL; + ctx->io_cbs.remove = NULL; + ctx->io_cbs.event = NULL; + ctx->io_cbs.event_priv = NULL; + } +} + + +/* This function returns the callback function for I/O. */ +void +gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs) +{ + *io_cbs = ctx->io_cbs; +} + + +/* This function sets the locale for the context CTX, or the default + locale if CTX is a null pointer. */ +gpgme_error_t +gpgme_set_locale (gpgme_ctx_t ctx, int category, const char *value) +{ + int failed = 0; + char *new_lc_ctype = NULL; + char *new_lc_messages = NULL; + +#define PREPARE_ONE_LOCALE(lcat, ucat) \ + if (!failed && value \ + && (category == LC_ALL || category == LC_ ## ucat)) \ + { \ + new_lc_ ## lcat = strdup (value); \ + if (!new_lc_ ## lcat) \ + failed = 1; \ + } + + PREPARE_ONE_LOCALE (ctype, CTYPE); +#ifdef LC_MESSAGES + PREPARE_ONE_LOCALE (messages, MESSAGES); +#endif + + if (failed) + { + int saved_errno = errno; + + if (new_lc_ctype) + free (new_lc_ctype); + if (new_lc_messages) + free (new_lc_messages); + + return gpg_error_from_errno (saved_errno); + } + +#define SET_ONE_LOCALE(lcat, ucat) \ + if (category == LC_ALL || category == LC_ ## ucat) \ + { \ + if (ctx) \ + { \ + if (ctx->lc_ ## lcat) \ + free (ctx->lc_ ## lcat); \ + ctx->lc_ ## lcat = new_lc_ ## lcat; \ + } \ + else \ + { \ + if (def_lc_ ## lcat) \ + free (def_lc_ ## lcat); \ + def_lc_ ## lcat = new_lc_ ## lcat; \ + } \ + } + + if (!ctx) + LOCK (def_lc_lock); + SET_ONE_LOCALE (ctype, CTYPE); +#ifdef LC_MESSAGES + SET_ONE_LOCALE (messages, MESSAGES); +#endif + if (!ctx) + UNLOCK (def_lc_lock); + + return 0; +} + + +/* Get the information about the configured engines. A pointer to the + first engine in the statically allocated linked list is returned. + The returned data is valid until the next gpgme_ctx_set_engine_info. */ +gpgme_engine_info_t +gpgme_ctx_get_engine_info (gpgme_ctx_t ctx) +{ + return ctx->engine_info; +} + + +/* Set the engine info for the context CTX, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t +gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto, + const char *file_name, const char *home_dir) +{ + /* Shut down the engine when changing engine info. */ + if (ctx->engine) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } + return _gpgme_set_engine_info (ctx->engine_info, proto, + file_name, home_dir); +} + + +/* Clear all notation data from the context. */ +void +gpgme_sig_notation_clear (gpgme_ctx_t ctx) +{ + gpgme_sig_notation_t notation; + + if (!ctx) + return; + + notation = ctx->sig_notations; + while (notation) + { + gpgme_sig_notation_t next_notation = notation->next; + _gpgme_sig_notation_free (notation); + notation = next_notation; + } +} + + +/* Add the human-readable notation data with name NAME and value VALUE + to the context CTX, using the flags FLAGS. If NAME is NULL, then + VALUE should be a policy URL. The flag + GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation + data, and false for policy URLs. */ +gpgme_error_t +gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, + const char *value, gpgme_sig_notation_flags_t flags) +{ + gpgme_error_t err; + gpgme_sig_notation_t notation; + gpgme_sig_notation_t *lastp; + + if (!ctx) + gpg_error (GPG_ERR_INV_VALUE); + + if (name) + flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; + else + flags &= ~GPGME_SIG_NOTATION_HUMAN_READABLE; + + err = _gpgme_sig_notation_create (¬ation, name, name ? strlen (name) : 0, + value, value ? strlen (value) : 0, flags); + if (err) + return err; + + lastp = &ctx->sig_notations; + while (*lastp) + lastp = &(*lastp)->next; + + *lastp = notation; + return 0; +} + + +/* Get the sig notations for this context. */ +gpgme_sig_notation_t +gpgme_sig_notation_get (gpgme_ctx_t ctx) +{ + if (!ctx) + return NULL; + + return ctx->sig_notations; +} + + +const char * +gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) +{ + switch (algo) + { + case GPGME_PK_RSA: + return "RSA"; + + case GPGME_PK_RSA_E: + return "RSA-E"; + + case GPGME_PK_RSA_S: + return "RSA-S"; + + case GPGME_PK_ELG_E: + return "ELG-E"; + + case GPGME_PK_DSA: + return "DSA"; + + case GPGME_PK_ELG: + return "ELG"; + + default: + return NULL; + } +} + + +const char * +gpgme_hash_algo_name (gpgme_hash_algo_t algo) +{ + switch (algo) + { + case GPGME_MD_MD5: + return "MD5"; + + case GPGME_MD_SHA1: + return "SHA1"; + + case GPGME_MD_RMD160: + return "RIPEMD160"; + + case GPGME_MD_MD2: + return "MD2"; + + case GPGME_MD_TIGER: + return "TIGER192"; + + case GPGME_MD_HAVAL: + return "HAVAL"; + + case GPGME_MD_SHA256: + return "SHA256"; + + case GPGME_MD_SHA384: + return "SHA384"; + + case GPGME_MD_SHA512: + return "SHA512"; + + case GPGME_MD_MD4: + return "MD4"; + + case GPGME_MD_CRC32: + return "CRC32"; + + case GPGME_MD_CRC32_RFC1510: + return "CRC32RFC1510"; + + case GPGME_MD_CRC24_RFC2440: + return "CRC24RFC2440"; + + default: + return NULL; + } +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/gpgme.h b/libkdenetwork/libgpgme-copy/gpgme/gpgme.h new file mode 100644 index 000000000..b8aa9e291 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/gpgme.h @@ -0,0 +1,1706 @@ +/* gpgme.h - Public interface to GnuPG Made Easy. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 GPGME_H +#define GPGME_H + +#ifdef __GNUC__ +#define _GPGME_INLINE __inline__ +#elif __STDC_VERSION__ >= 199901L +#define _GPGME_INLINE inline +#else +#define _GPGME_INLINE +#endif + +/* Include stdio.h for the FILE type definition. */ +#include <stdio.h> + +#ifdef _MSC_VER + typedef long off_t; + typedef long ssize_t; +#else +# include <sys/types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#if 0 /* just to make Emacs auto-indent happy */ +} +#endif +#endif /* __cplusplus */ + +#include <gpg-error.h> + + +/* Check for compiler features. */ +#if __GNUC__ +#define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +#if _GPGME_GCC_VERSION > 30100 +#define _GPGME_DEPRECATED __attribute__ ((__deprecated__)) +#endif +#endif + +#ifndef _GPGME_DEPRECATED +#define _GPGME_DEPRECATED +#endif + + +/* The version of this header should match the one of the library. Do + not use this symbol in your application, use gpgme_check_version + instead. The purpose of this macro is to let autoconf (using the + AM_PATH_GPGME macro) check that this header matches the installed + library. Warning: Do not edit the next line. configure will do + that for you! */ +#define GPGME_VERSION "1.1.4" + + + +/* Some opaque data types used by GPGME. */ + +/* The context holds some global state and configration options, as + well as the results of a crypto operation. */ +struct gpgme_context; +typedef struct gpgme_context *gpgme_ctx_t; + +/* The data object is used by GPGME to exchange arbitrary data. */ +struct gpgme_data; +typedef struct gpgme_data *gpgme_data_t; + + +/* Wrappers for the libgpg-error library. */ + +typedef gpg_error_t gpgme_error_t; +typedef gpg_err_code_t gpgme_err_code_t; +typedef gpg_err_source_t gpgme_err_source_t; + + +static _GPGME_INLINE gpgme_error_t +gpgme_err_make (gpgme_err_source_t source, gpgme_err_code_t code) +{ + return gpg_err_make (source, code); +} + + +/* The user can define GPGME_ERR_SOURCE_DEFAULT before including this + file to specify a default source for gpgme_error. */ +#ifndef GPGME_ERR_SOURCE_DEFAULT +#define GPGME_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1 +#endif + +static _GPGME_INLINE gpgme_error_t +gpgme_error (gpgme_err_code_t code) +{ + return gpgme_err_make (GPGME_ERR_SOURCE_DEFAULT, code); +} + + +static _GPGME_INLINE gpgme_err_code_t +gpgme_err_code (gpgme_error_t err) +{ + return gpg_err_code (err); +} + + +static _GPGME_INLINE gpgme_err_source_t +gpgme_err_source (gpgme_error_t err) +{ + return gpg_err_source (err); +} + + +/* Return a pointer to a string containing a description of the error + code in the error value ERR. This function is not thread safe. */ +const char *gpgme_strerror (gpgme_error_t err); + +/* Return the error string for ERR in the user-supplied buffer BUF of + size BUFLEN. This function is, in contrast to gpg_strerror, + thread-safe if a thread-safe strerror_r() function is provided by + the system. If the function succeeds, 0 is returned and BUF + contains the string describing the error. If the buffer was not + large enough, ERANGE is returned and BUF contains as much of the + beginning of the error string as fits into the buffer. */ +int gpgme_strerror_r (gpg_error_t err, char *buf, size_t buflen); + + +/* Return a pointer to a string containing a description of the error + source in the error value ERR. */ +const char *gpgme_strsource (gpgme_error_t err); + + +/* Retrieve the error code for the system error ERR. This returns + GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report + this). */ +gpgme_err_code_t gpgme_err_code_from_errno (int err); + + +/* Retrieve the system error for the error code CODE. This returns 0 + if CODE is not a system error code. */ +int gpgme_err_code_to_errno (gpgme_err_code_t code); + + +/* Return an error value with the error source SOURCE and the system + error ERR. */ +gpgme_error_t gpgme_err_make_from_errno (gpgme_err_source_t source, int err); + + +/* Return an error value with the system error ERR. */ +gpgme_err_code_t gpgme_error_from_errno (int err); + + +/* The possible encoding mode of gpgme_data_t objects. */ +typedef enum + { + GPGME_DATA_ENCODING_NONE = 0, /* Not specified. */ + GPGME_DATA_ENCODING_BINARY = 1, + GPGME_DATA_ENCODING_BASE64 = 2, + GPGME_DATA_ENCODING_ARMOR = 3 /* Either PEM or OpenPGP Armor. */ + } +gpgme_data_encoding_t; + + +/* Public key algorithms from libgcrypt. */ +typedef enum + { + GPGME_PK_RSA = 1, + GPGME_PK_RSA_E = 2, + GPGME_PK_RSA_S = 3, + GPGME_PK_ELG_E = 16, + GPGME_PK_DSA = 17, + GPGME_PK_ELG = 20 + } +gpgme_pubkey_algo_t; + + +/* Hash algorithms from libgcrypt. */ +typedef enum + { + GPGME_MD_NONE = 0, + GPGME_MD_MD5 = 1, + GPGME_MD_SHA1 = 2, + GPGME_MD_RMD160 = 3, + GPGME_MD_MD2 = 5, + GPGME_MD_TIGER = 6, /* TIGER/192. */ + GPGME_MD_HAVAL = 7, /* HAVAL, 5 pass, 160 bit. */ + GPGME_MD_SHA256 = 8, + GPGME_MD_SHA384 = 9, + GPGME_MD_SHA512 = 10, + GPGME_MD_MD4 = 301, + GPGME_MD_CRC32 = 302, + GPGME_MD_CRC32_RFC1510 = 303, + GPGME_MD_CRC24_RFC2440 = 304 + } +gpgme_hash_algo_t; + + +/* The possible signature stati. Deprecated, use error value in sig + status. */ +typedef enum + { + GPGME_SIG_STAT_NONE = 0, + GPGME_SIG_STAT_GOOD = 1, + GPGME_SIG_STAT_BAD = 2, + GPGME_SIG_STAT_NOKEY = 3, + GPGME_SIG_STAT_NOSIG = 4, + GPGME_SIG_STAT_ERROR = 5, + GPGME_SIG_STAT_DIFF = 6, + GPGME_SIG_STAT_GOOD_EXP = 7, + GPGME_SIG_STAT_GOOD_EXPKEY = 8 + } +_gpgme_sig_stat_t; +typedef _gpgme_sig_stat_t gpgme_sig_stat_t _GPGME_DEPRECATED; + + +/* The available signature modes. */ +typedef enum + { + GPGME_SIG_MODE_NORMAL = 0, + GPGME_SIG_MODE_DETACH = 1, + GPGME_SIG_MODE_CLEAR = 2 + } +gpgme_sig_mode_t; + + +/* The available key and signature attributes. Deprecated, use the + individual result structures instead. */ +typedef enum + { + GPGME_ATTR_KEYID = 1, + GPGME_ATTR_FPR = 2, + GPGME_ATTR_ALGO = 3, + GPGME_ATTR_LEN = 4, + GPGME_ATTR_CREATED = 5, + GPGME_ATTR_EXPIRE = 6, + GPGME_ATTR_OTRUST = 7, + GPGME_ATTR_USERID = 8, + GPGME_ATTR_NAME = 9, + GPGME_ATTR_EMAIL = 10, + GPGME_ATTR_COMMENT = 11, + GPGME_ATTR_VALIDITY = 12, + GPGME_ATTR_LEVEL = 13, + GPGME_ATTR_TYPE = 14, + GPGME_ATTR_IS_SECRET = 15, + GPGME_ATTR_KEY_REVOKED = 16, + GPGME_ATTR_KEY_INVALID = 17, + GPGME_ATTR_UID_REVOKED = 18, + GPGME_ATTR_UID_INVALID = 19, + GPGME_ATTR_KEY_CAPS = 20, + GPGME_ATTR_CAN_ENCRYPT = 21, + GPGME_ATTR_CAN_SIGN = 22, + GPGME_ATTR_CAN_CERTIFY = 23, + GPGME_ATTR_KEY_EXPIRED = 24, + GPGME_ATTR_KEY_DISABLED = 25, + GPGME_ATTR_SERIAL = 26, + GPGME_ATTR_ISSUER = 27, + GPGME_ATTR_CHAINID = 28, + GPGME_ATTR_SIG_STATUS = 29, + GPGME_ATTR_ERRTOK = 30, + GPGME_ATTR_SIG_SUMMARY = 31, + GPGME_ATTR_SIG_CLASS = 32 + } +_gpgme_attr_t; +typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED; + + +/* The available validities for a trust item or key. */ +typedef enum + { + GPGME_VALIDITY_UNKNOWN = 0, + GPGME_VALIDITY_UNDEFINED = 1, + GPGME_VALIDITY_NEVER = 2, + GPGME_VALIDITY_MARGINAL = 3, + GPGME_VALIDITY_FULL = 4, + GPGME_VALIDITY_ULTIMATE = 5 + } +gpgme_validity_t; + + +/* The available protocols. */ +typedef enum + { + GPGME_PROTOCOL_OpenPGP = 0, /* The default mode. */ + GPGME_PROTOCOL_CMS = 1 + } +gpgme_protocol_t; + + +/* The available keylist mode flags. */ +#define GPGME_KEYLIST_MODE_LOCAL 1 +#define GPGME_KEYLIST_MODE_EXTERN 2 +#define GPGME_KEYLIST_MODE_SIGS 4 +#define GPGME_KEYLIST_MODE_SIG_NOTATIONS 8 +#define GPGME_KEYLIST_MODE_VALIDATE 256 + +typedef unsigned int gpgme_keylist_mode_t; + + +/* Signature notations. */ + +/* The available signature notation flags. */ +#define GPGME_SIG_NOTATION_HUMAN_READABLE 1 +#define GPGME_SIG_NOTATION_CRITICAL 2 + +typedef unsigned int gpgme_sig_notation_flags_t; + +struct _gpgme_sig_notation +{ + struct _gpgme_sig_notation *next; + + /* If NAME is a null pointer, then VALUE contains a policy URL + rather than a notation. */ + char *name; + + /* The value of the notation data. */ + char *value; + + /* The length of the name of the notation data. */ + int name_len; + + /* The length of the value of the notation data. */ + int value_len; + + /* The accumulated flags. */ + gpgme_sig_notation_flags_t flags; + + /* Notation data is human-readable. */ + unsigned int human_readable : 1; + + /* Notation data is critical. */ + unsigned int critical : 1; + + /* Internal to GPGME, do not use. */ + int _unused : 30; +}; +typedef struct _gpgme_sig_notation *gpgme_sig_notation_t; + + +/* The possible stati for the edit operation. */ +typedef enum + { + GPGME_STATUS_EOF, + /* mkstatus processing starts here */ + GPGME_STATUS_ENTER, + GPGME_STATUS_LEAVE, + GPGME_STATUS_ABORT, + + GPGME_STATUS_GOODSIG, + GPGME_STATUS_BADSIG, + GPGME_STATUS_ERRSIG, + + GPGME_STATUS_BADARMOR, + + GPGME_STATUS_RSA_OR_IDEA, + GPGME_STATUS_KEYEXPIRED, + GPGME_STATUS_KEYREVOKED, + + GPGME_STATUS_TRUST_UNDEFINED, + GPGME_STATUS_TRUST_NEVER, + GPGME_STATUS_TRUST_MARGINAL, + GPGME_STATUS_TRUST_FULLY, + GPGME_STATUS_TRUST_ULTIMATE, + + GPGME_STATUS_SHM_INFO, + GPGME_STATUS_SHM_GET, + GPGME_STATUS_SHM_GET_BOOL, + GPGME_STATUS_SHM_GET_HIDDEN, + + GPGME_STATUS_NEED_PASSPHRASE, + GPGME_STATUS_VALIDSIG, + GPGME_STATUS_SIG_ID, + GPGME_STATUS_ENC_TO, + GPGME_STATUS_NODATA, + GPGME_STATUS_BAD_PASSPHRASE, + GPGME_STATUS_NO_PUBKEY, + GPGME_STATUS_NO_SECKEY, + GPGME_STATUS_NEED_PASSPHRASE_SYM, + GPGME_STATUS_DECRYPTION_FAILED, + GPGME_STATUS_DECRYPTION_OKAY, + GPGME_STATUS_MISSING_PASSPHRASE, + GPGME_STATUS_GOOD_PASSPHRASE, + GPGME_STATUS_GOODMDC, + GPGME_STATUS_BADMDC, + GPGME_STATUS_ERRMDC, + GPGME_STATUS_IMPORTED, + GPGME_STATUS_IMPORT_OK, + GPGME_STATUS_IMPORT_PROBLEM, + GPGME_STATUS_IMPORT_RES, + GPGME_STATUS_FILE_START, + GPGME_STATUS_FILE_DONE, + GPGME_STATUS_FILE_ERROR, + + GPGME_STATUS_BEGIN_DECRYPTION, + GPGME_STATUS_END_DECRYPTION, + GPGME_STATUS_BEGIN_ENCRYPTION, + GPGME_STATUS_END_ENCRYPTION, + + GPGME_STATUS_DELETE_PROBLEM, + GPGME_STATUS_GET_BOOL, + GPGME_STATUS_GET_LINE, + GPGME_STATUS_GET_HIDDEN, + GPGME_STATUS_GOT_IT, + GPGME_STATUS_PROGRESS, + GPGME_STATUS_SIG_CREATED, + GPGME_STATUS_SESSION_KEY, + GPGME_STATUS_NOTATION_NAME, + GPGME_STATUS_NOTATION_DATA, + GPGME_STATUS_POLICY_URL, + GPGME_STATUS_BEGIN_STREAM, + GPGME_STATUS_END_STREAM, + GPGME_STATUS_KEY_CREATED, + GPGME_STATUS_USERID_HINT, + GPGME_STATUS_UNEXPECTED, + GPGME_STATUS_INV_RECP, + GPGME_STATUS_NO_RECP, + GPGME_STATUS_ALREADY_SIGNED, + GPGME_STATUS_SIGEXPIRED, + GPGME_STATUS_EXPSIG, + GPGME_STATUS_EXPKEYSIG, + GPGME_STATUS_TRUNCATED, + GPGME_STATUS_ERROR, + GPGME_STATUS_NEWSIG, + GPGME_STATUS_REVKEYSIG, + GPGME_STATUS_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, + GPGME_STATUS_PKA_TRUST_BAD, + GPGME_STATUS_PKA_TRUST_GOOD, + + GPGME_STATUS_PLAINTEXT + } +gpgme_status_code_t; + + +/* The engine information structure. */ +struct _gpgme_engine_info +{ + struct _gpgme_engine_info *next; + + /* The protocol ID. */ + gpgme_protocol_t protocol; + + /* The file name of the engine binary. */ + char *file_name; + + /* The version string of the installed engine. */ + char *version; + + /* The minimum version required for GPGME. */ + const char *req_version; + + /* The home directory used, or NULL if default. */ + char *home_dir; +}; +typedef struct _gpgme_engine_info *gpgme_engine_info_t; + + +/* A subkey from a key. */ +struct _gpgme_subkey +{ + struct _gpgme_subkey *next; + + /* True if subkey is revoked. */ + unsigned int revoked : 1; + + /* True if subkey is expired. */ + unsigned int expired : 1; + + /* True if subkey is disabled. */ + unsigned int disabled : 1; + + /* True if subkey is invalid. */ + unsigned int invalid : 1; + + /* True if subkey can be used for encryption. */ + unsigned int can_encrypt : 1; + + /* True if subkey can be used for signing. */ + unsigned int can_sign : 1; + + /* True if subkey can be used for certification. */ + unsigned int can_certify : 1; + + /* True if subkey is secret. */ + unsigned int secret : 1; + + /* True if subkey can be used for authentication. */ + unsigned int can_authenticate : 1; + + /* True if subkey is qualified for signatures according to German law. */ + unsigned int is_qualified : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 22; + + /* Public key algorithm supported by this subkey. */ + gpgme_pubkey_algo_t pubkey_algo; + + /* Length of the subkey. */ + unsigned int length; + + /* The key ID of the subkey. */ + char *keyid; + + /* Internal to GPGME, do not use. */ + char _keyid[16 + 1]; + + /* The fingerprint of the subkey in hex digit form. */ + char *fpr; + + /* The creation timestamp, -1 if invalid, 0 if not available. */ + long int timestamp; + + /* The expiration timestamp, 0 if the subkey does not expire. */ + long int expires; +}; +typedef struct _gpgme_subkey *gpgme_subkey_t; + + +/* A signature on a user ID. */ +struct _gpgme_key_sig +{ + struct _gpgme_key_sig *next; + + /* True if the signature is a revocation signature. */ + unsigned int revoked : 1; + + /* True if the signature is expired. */ + unsigned int expired : 1; + + /* True if the signature is invalid. */ + unsigned int invalid : 1; + + /* True if the signature should be exported. */ + unsigned int exportable : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 28; + + /* The public key algorithm used to create the signature. */ + gpgme_pubkey_algo_t pubkey_algo; + + /* The key ID of key used to create the signature. */ + char *keyid; + + /* Internal to GPGME, do not use. */ + char _keyid[16 + 1]; + + /* The creation timestamp, -1 if invalid, 0 if not available. */ + long int timestamp; + + /* The expiration timestamp, 0 if the subkey does not expire. */ + long int expires; + + /* Same as in gpgme_signature_t. */ + gpgme_error_t status; + +#ifdef __cplusplus + unsigned int _obsolete_class _GPGME_DEPRECATED; +#else + /* Must be set to SIG_CLASS below. */ + unsigned int class _GPGME_DEPRECATED; +#endif + + /* The user ID string. */ + char *uid; + + /* The name part of the user ID. */ + char *name; + + /* The email part of the user ID. */ + char *email; + + /* The comment part of the user ID. */ + char *comment; + + /* Crypto backend specific signature class. */ + unsigned int sig_class; + + /* Notation data and policy URLs. */ + gpgme_sig_notation_t notations; + + /* Internal to GPGME, do not use. */ + gpgme_sig_notation_t _last_notation; +}; +typedef struct _gpgme_key_sig *gpgme_key_sig_t; + + +/* An user ID from a key. */ +struct _gpgme_user_id +{ + struct _gpgme_user_id *next; + + /* True if the user ID is revoked. */ + unsigned int revoked : 1; + + /* True if the user ID is invalid. */ + unsigned int invalid : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 30; + + /* The validity of the user ID. */ + gpgme_validity_t validity; + + /* The user ID string. */ + char *uid; + + /* The name part of the user ID. */ + char *name; + + /* The email part of the user ID. */ + char *email; + + /* The comment part of the user ID. */ + char *comment; + + /* The signatures of the user ID. */ + gpgme_key_sig_t signatures; + + /* Internal to GPGME, do not use. */ + gpgme_key_sig_t _last_keysig; +}; +typedef struct _gpgme_user_id *gpgme_user_id_t; + + +/* A key from the keyring. */ +struct _gpgme_key +{ + /* Internal to GPGME, do not use. */ + unsigned int _refs; + + /* True if key is revoked. */ + unsigned int revoked : 1; + + /* True if key is expired. */ + unsigned int expired : 1; + + /* True if key is disabled. */ + unsigned int disabled : 1; + + /* True if key is invalid. */ + unsigned int invalid : 1; + + /* True if key can be used for encryption. */ + unsigned int can_encrypt : 1; + + /* True if key can be used for signing. */ + unsigned int can_sign : 1; + + /* True if key can be used for certification. */ + unsigned int can_certify : 1; + + /* True if key is secret. */ + unsigned int secret : 1; + + /* True if key can be used for authentication. */ + unsigned int can_authenticate : 1; + + /* True if subkey is qualified for signatures according to German law. */ + unsigned int is_qualified : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 22; + + /* This is the protocol supported by this key. */ + gpgme_protocol_t protocol; + + /* If protocol is GPGME_PROTOCOL_CMS, this string contains the + issuer serial. */ + char *issuer_serial; + + /* If protocol is GPGME_PROTOCOL_CMS, this string contains the + issuer name. */ + char *issuer_name; + + /* If protocol is GPGME_PROTOCOL_CMS, this string contains the chain + ID. */ + char *chain_id; + + /* If protocol is GPGME_PROTOCOL_OpenPGP, this field contains the + owner trust. */ + gpgme_validity_t owner_trust; + + /* The subkeys of the key. */ + gpgme_subkey_t subkeys; + + /* The user IDs of the key. */ + gpgme_user_id_t uids; + + /* Internal to GPGME, do not use. */ + gpgme_subkey_t _last_subkey; + + /* Internal to GPGME, do not use. */ + gpgme_user_id_t _last_uid; + + /* The keylist mode that was active when listing the key. */ + gpgme_keylist_mode_t keylist_mode; +}; +typedef struct _gpgme_key *gpgme_key_t; + + + +/* Types for callback functions. */ + +/* Request a passphrase from the user. */ +typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook, + const char *uid_hint, + const char *passphrase_info, + int prev_was_bad, int fd); + +/* Inform the user about progress made. */ +typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what, + int type, int current, int total); + +/* Interact with the user about an edit operation. */ +typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque, + gpgme_status_code_t status, + const char *args, int fd); + + +/* Context management functions. */ + +/* Create a new context and return it in CTX. */ +gpgme_error_t gpgme_new (gpgme_ctx_t *ctx); + +/* Release the context CTX. */ +void gpgme_release (gpgme_ctx_t ctx); + +/* Set the protocol to be used by CTX to PROTO. */ +gpgme_error_t gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t proto); + +/* Get the protocol used with CTX */ +gpgme_protocol_t gpgme_get_protocol (gpgme_ctx_t ctx); + +/* Get the string describing protocol PROTO, or NULL if invalid. */ +const char *gpgme_get_protocol_name (gpgme_protocol_t proto); + +/* If YES is non-zero, enable armor mode in CTX, disable it otherwise. */ +void gpgme_set_armor (gpgme_ctx_t ctx, int yes); + +/* Return non-zero if armor mode is set in CTX. */ +int gpgme_get_armor (gpgme_ctx_t ctx); + +/* If YES is non-zero, enable text mode in CTX, disable it otherwise. */ +void gpgme_set_textmode (gpgme_ctx_t ctx, int yes); + +/* Return non-zero if text mode is set in CTX. */ +int gpgme_get_textmode (gpgme_ctx_t ctx); + +/* Use whatever the default of the backend crypto engine is. */ +#define GPGME_INCLUDE_CERTS_DEFAULT -256 + +/* Include up to NR_OF_CERTS certificates in an S/MIME message. */ +void gpgme_set_include_certs (gpgme_ctx_t ctx, int nr_of_certs); + +/* Return the number of certs to include in an S/MIME message. */ +int gpgme_get_include_certs (gpgme_ctx_t ctx); + +/* Set keylist mode in CTX to MODE. */ +gpgme_error_t gpgme_set_keylist_mode (gpgme_ctx_t ctx, + gpgme_keylist_mode_t mode); + +/* Get keylist mode in CTX. */ +gpgme_keylist_mode_t gpgme_get_keylist_mode (gpgme_ctx_t ctx); + +/* Set the passphrase callback function in CTX to CB. HOOK_VALUE is + passed as first argument to the passphrase callback function. */ +void gpgme_set_passphrase_cb (gpgme_ctx_t ctx, + gpgme_passphrase_cb_t cb, void *hook_value); + +/* Get the current passphrase callback function in *CB and the current + hook value in *HOOK_VALUE. */ +void gpgme_get_passphrase_cb (gpgme_ctx_t ctx, gpgme_passphrase_cb_t *cb, + void **hook_value); + +/* Set the progress callback function in CTX to CB. HOOK_VALUE is + passed as first argument to the progress callback function. */ +void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb, + void *hook_value); + +/* Get the current progress callback function in *CB and the current + hook value in *HOOK_VALUE. */ +void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb, + void **hook_value); + +/* This function sets the locale for the context CTX, or the default + locale if CTX is a null pointer. */ +gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category, + const char *value); + +/* Get the information about the configured engines. A pointer to the + first engine in the statically allocated linked list is returned. + The returned data is valid until the next gpgme_ctx_set_engine_info. */ +gpgme_engine_info_t gpgme_ctx_get_engine_info (gpgme_ctx_t ctx); + +/* Set the engine info for the context CTX, protocol PROTO, to the + file name FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, + gpgme_protocol_t proto, + const char *file_name, + const char *home_dir); + + +/* Return a statically allocated string with the name of the public + key algorithm ALGO, or NULL if that name is not known. */ +const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo); + +/* Return a statically allocated string with the name of the hash + algorithm ALGO, or NULL if that name is not known. */ +const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo); + + +/* Delete all signers from CTX. */ +void gpgme_signers_clear (gpgme_ctx_t ctx); + +/* Add KEY to list of signers in CTX. */ +gpgme_error_t gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key); + +/* Return the SEQth signer's key in CTX. */ +gpgme_key_t gpgme_signers_enum (const gpgme_ctx_t ctx, int seq); + +/* Retrieve the signature status of signature IDX in CTX after a + successful verify operation in R_STAT (if non-null). The creation + time stamp of the signature is returned in R_CREATED (if non-null). + The function returns a string containing the fingerprint. + Deprecated, use verify result directly. */ +const char *gpgme_get_sig_status (gpgme_ctx_t ctx, int idx, + _gpgme_sig_stat_t *r_stat, + time_t *r_created) _GPGME_DEPRECATED; + +/* Retrieve certain attributes of a signature. IDX is the index + number of the signature after a successful verify operation. WHAT + is an attribute where GPGME_ATTR_EXPIRE is probably the most useful + one. WHATIDX is to be passed as 0 for most attributes . */ +unsigned long gpgme_get_sig_ulong_attr (gpgme_ctx_t c, int idx, + _gpgme_attr_t what, int whatidx) + _GPGME_DEPRECATED; +const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx, + _gpgme_attr_t what, int whatidx) + _GPGME_DEPRECATED; + + +/* Get the key used to create signature IDX in CTX and return it in + R_KEY. */ +gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) + _GPGME_DEPRECATED; + + +/* Clear all notation data from the context. */ +void gpgme_sig_notation_clear (gpgme_ctx_t ctx); + +/* Add the human-readable notation data with name NAME and value VALUE + to the context CTX, using the flags FLAGS. If NAME is NULL, then + VALUE should be a policy URL. The flag + GPGME_SIG_NOTATION_HUMAN_READABLE is forced to be true for notation + data, and false for policy URLs. */ +gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, + const char *value, + gpgme_sig_notation_flags_t flags); + +/* Get the sig notations for this context. */ +gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx); + + +/* Run control. */ + +/* The type of an I/O callback function. */ +typedef gpgme_error_t (*gpgme_io_cb_t) (void *data, int fd); + +/* The type of a function that can register FNC as the I/O callback + function for the file descriptor FD with direction dir (0: for writing, + 1: for reading). FNC_DATA should be passed as DATA to FNC. The + function should return a TAG suitable for the corresponding + gpgme_remove_io_cb_t, and an error value. */ +typedef gpgme_error_t (*gpgme_register_io_cb_t) (void *data, int fd, int dir, + gpgme_io_cb_t fnc, + void *fnc_data, void **tag); + +/* The type of a function that can remove a previously registered I/O + callback function given TAG as returned by the register + function. */ +typedef void (*gpgme_remove_io_cb_t) (void *tag); + +typedef enum + { + GPGME_EVENT_START, + GPGME_EVENT_DONE, + GPGME_EVENT_NEXT_KEY, + GPGME_EVENT_NEXT_TRUSTITEM + } +gpgme_event_io_t; + +/* The type of a function that is called when a context finished an + operation. */ +typedef void (*gpgme_event_io_cb_t) (void *data, gpgme_event_io_t type, + void *type_data); + +struct gpgme_io_cbs +{ + gpgme_register_io_cb_t add; + void *add_priv; + gpgme_remove_io_cb_t remove; + gpgme_event_io_cb_t event; + void *event_priv; +}; +typedef struct gpgme_io_cbs *gpgme_io_cbs_t; + +/* Set the I/O callback functions in CTX to IO_CBS. */ +void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs); + +/* Get the current I/O callback functions. */ +void gpgme_get_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs); + +/* Process the pending operation and, if HANG is non-zero, wait for + the pending operation to finish. */ +gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang); + + +/* Functions to handle data objects. */ + +/* Read up to SIZE bytes into buffer BUFFER from the data object with + the handle HANDLE. Return the number of characters read, 0 on EOF + and -1 on error. If an error occurs, errno is set. */ +typedef ssize_t (*gpgme_data_read_cb_t) (void *handle, void *buffer, + size_t size); + +/* Write up to SIZE bytes from buffer BUFFER to the data object with + the handle HANDLE. Return the number of characters written, or -1 + on error. If an error occurs, errno is set. */ +typedef ssize_t (*gpgme_data_write_cb_t) (void *handle, const void *buffer, + size_t size); + +/* Set the current position from where the next read or write starts + in the data object with the handle HANDLE to OFFSET, relativ to + WHENCE. */ +typedef off_t (*gpgme_data_seek_cb_t) (void *handle, off_t offset, int whence); + +/* Close the data object with the handle DL. */ +typedef void (*gpgme_data_release_cb_t) (void *handle); + +struct gpgme_data_cbs +{ + gpgme_data_read_cb_t read; + gpgme_data_write_cb_t write; + gpgme_data_seek_cb_t seek; + gpgme_data_release_cb_t release; +}; +typedef struct gpgme_data_cbs *gpgme_data_cbs_t; + +/* Read up to SIZE bytes into buffer BUFFER from the data object with + the handle DH. Return the number of characters read, 0 on EOF and + -1 on error. If an error occurs, errno is set. */ +ssize_t gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size); + +/* Write up to SIZE bytes from buffer BUFFER to the data object with + the handle DH. Return the number of characters written, or -1 on + error. If an error occurs, errno is set. */ +ssize_t gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size); + +/* Set the current position from where the next read or write starts + in the data object with the handle DH to OFFSET, relativ to + WHENCE. */ +off_t gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence); + +/* Create a new data buffer and return it in R_DH. */ +gpgme_error_t gpgme_data_new (gpgme_data_t *r_dh); + +/* Destroy the data buffer DH. */ +void gpgme_data_release (gpgme_data_t dh); + +/* Create a new data buffer filled with SIZE bytes starting from + BUFFER. If COPY is zero, copying is delayed until necessary, and + the data is taken from the original location when needed. */ +gpgme_error_t gpgme_data_new_from_mem (gpgme_data_t *r_dh, + const char *buffer, size_t size, + int copy); + +/* Destroy the data buffer DH and return a pointer to its content. + The memory has be to released with 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); + +/* Release the memory returned by gpgme_data_release_and_get_mem(). */ +void gpgme_free (void *buffer); + +gpgme_error_t gpgme_data_new_from_cbs (gpgme_data_t *dh, + gpgme_data_cbs_t cbs, + void *handle); + +gpgme_error_t gpgme_data_new_from_fd (gpgme_data_t *dh, int fd); + +gpgme_error_t gpgme_data_new_from_stream (gpgme_data_t *dh, FILE *stream); + +/* Return the encoding attribute of the data buffer DH */ +gpgme_data_encoding_t gpgme_data_get_encoding (gpgme_data_t dh); + +/* Set the encoding attribute of data buffer DH to ENC */ +gpgme_error_t gpgme_data_set_encoding (gpgme_data_t dh, + gpgme_data_encoding_t enc); + +/* 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); + +/* 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); + + +/* Create a new data buffer which retrieves the data from the callback + function READ_CB. Deprecated, please use gpgme_data_new_from_cbs + instead. */ +gpgme_error_t gpgme_data_new_with_read_cb (gpgme_data_t *r_dh, + int (*read_cb) (void*,char *, + size_t,size_t*), + void *read_cb_value) + _GPGME_DEPRECATED; + +/* Create a new data buffer filled with the content of file FNAME. + COPY must be non-zero. For delayed read, please use + gpgme_data_new_from_fd or gpgme_data_new_from stream instead. */ +gpgme_error_t gpgme_data_new_from_file (gpgme_data_t *r_dh, + const char *fname, + int copy); + +/* Create a new data buffer filled with LENGTH bytes starting from + OFFSET within the file FNAME or stream FP (exactly one must be + non-zero). */ +gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh, + const char *fname, FILE *fp, + off_t offset, size_t length); + +/* Reset the read pointer in DH. Deprecated, please use + gpgme_data_seek instead. */ +gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED; + + +/* Key and trust functions. */ + +/* Get the key with the fingerprint FPR from the crypto backend. If + SECRET is true, get the secret key. */ +gpgme_error_t gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, + gpgme_key_t *r_key, int secret); + +/* Acquire a reference to KEY. */ +void gpgme_key_ref (gpgme_key_t key); + +/* Release a reference to KEY. If this was the last one the key is + destroyed. */ +void gpgme_key_unref (gpgme_key_t key); +void gpgme_key_release (gpgme_key_t key); + +/* Return the value of the attribute WHAT of KEY, which has to be + representable by a string. IDX specifies the sub key or user ID + for attributes related to sub keys or user IDs. Deprecated, use + key structure directly instead. */ +const char *gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + +/* Return the value of the attribute WHAT of KEY, which has to be + representable by an unsigned integer. IDX specifies the sub key or + user ID for attributes related to sub keys or user IDs. + Deprecated, use key structure directly instead. */ +unsigned long gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + +/* Return the value of the attribute WHAT of a signature on user ID + UID_IDX in KEY, which has to be representable by a string. IDX + specifies the signature. Deprecated, use key structure directly + instead. */ +const char *gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx, + _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + +/* Return the value of the attribute WHAT of a signature on user ID + UID_IDX in KEY, which has to be representable by an unsigned + integer string. IDX specifies the signature. Deprecated, use key + structure directly instead. */ +unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, + _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + + +/* Crypto Operations. */ + +/* Cancel a pending asynchronous operation. */ +gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx); + + +struct _gpgme_invalid_key +{ + struct _gpgme_invalid_key *next; + char *fpr; + gpgme_error_t reason; +}; +typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; + + +/* Encryption. */ +struct _gpgme_op_encrypt_result +{ + /* The list of invalid recipients. */ + gpgme_invalid_key_t invalid_recipients; +}; +typedef struct _gpgme_op_encrypt_result *gpgme_encrypt_result_t; + +/* Retrieve a pointer to the result of the encrypt operation. */ +gpgme_encrypt_result_t gpgme_op_encrypt_result (gpgme_ctx_t ctx); + +/* The valid encryption flags. */ +typedef enum + { + GPGME_ENCRYPT_ALWAYS_TRUST = 1 + } +gpgme_encrypt_flags_t; + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + store the resulting ciphertext in CIPHER. */ +gpgme_error_t gpgme_op_encrypt_start (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher); + +/* Encrypt plaintext PLAIN within CTX for the recipients RECP and + store the resulting ciphertext in CIPHER. Also sign the ciphertext + with the signers in CTX. */ +gpgme_error_t gpgme_op_encrypt_sign_start (gpgme_ctx_t ctx, + gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, + gpgme_data_t cipher); +gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, + gpgme_data_t plain, gpgme_data_t cipher); + + +/* Decryption. */ + +struct _gpgme_recipient +{ + struct _gpgme_recipient *next; + + /* The key ID of key for which the text was encrypted. */ + char *keyid; + + /* Internal to GPGME, do not use. */ + char _keyid[16 + 1]; + + /* The public key algorithm of the recipient key. */ + gpgme_pubkey_algo_t pubkey_algo; + + /* The status of the recipient. */ + gpgme_error_t status; +}; +typedef struct _gpgme_recipient *gpgme_recipient_t; + +struct _gpgme_op_decrypt_result +{ + char *unsupported_algorithm; + + /* Key should not have been used for encryption. */ + unsigned int wrong_key_usage : 1; + + /* Internal to GPGME, do not use. */ + int _unused : 31; + + gpgme_recipient_t recipients; + + /* The original file name of the plaintext message, if + available. */ + char *file_name; +}; +typedef struct _gpgme_op_decrypt_result *gpgme_decrypt_result_t; + +/* Retrieve a pointer to the result of the decrypt operation. */ +gpgme_decrypt_result_t gpgme_op_decrypt_result (gpgme_ctx_t ctx); + +/* Decrypt ciphertext CIPHER within CTX and store the resulting + plaintext in PLAIN. */ +gpgme_error_t gpgme_op_decrypt_start (gpgme_ctx_t ctx, gpgme_data_t cipher, + gpgme_data_t plain); +gpgme_error_t gpgme_op_decrypt (gpgme_ctx_t ctx, + gpgme_data_t cipher, gpgme_data_t plain); + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t gpgme_op_decrypt_verify_start (gpgme_ctx_t ctx, + gpgme_data_t cipher, + gpgme_data_t plain); +gpgme_error_t gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher, + gpgme_data_t plain); + + +/* Signing. */ +struct _gpgme_new_signature +{ + struct _gpgme_new_signature *next; + + /* The type of the signature. */ + gpgme_sig_mode_t type; + + /* The public key algorithm used to create the signature. */ + gpgme_pubkey_algo_t pubkey_algo; + + /* The hash algorithm used to create the signature. */ + gpgme_hash_algo_t hash_algo; + + /* Internal to GPGME, do not use. Must be set to the same value as + CLASS below. */ + unsigned long _obsolete_class; + + /* Signature creation time. */ + long int timestamp; + + /* The fingerprint of the signature. */ + char *fpr; + +#ifdef __cplusplus + unsigned int _obsolete_class_2; +#else + /* Must be set to SIG_CLASS below. */ + unsigned int class _GPGME_DEPRECATED; +#endif + + /* Crypto backend specific signature class. */ + unsigned int sig_class; +}; +typedef struct _gpgme_new_signature *gpgme_new_signature_t; + +struct _gpgme_op_sign_result +{ + /* The list of invalid signers. */ + gpgme_invalid_key_t invalid_signers; + gpgme_new_signature_t signatures; +}; +typedef struct _gpgme_op_sign_result *gpgme_sign_result_t; + +/* Retrieve a pointer to the result of the signing operation. */ +gpgme_sign_result_t gpgme_op_sign_result (gpgme_ctx_t ctx); + +/* Sign the plaintext PLAIN and store the signature in SIG. */ +gpgme_error_t gpgme_op_sign_start (gpgme_ctx_t ctx, + gpgme_data_t plain, gpgme_data_t sig, + gpgme_sig_mode_t mode); +gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx, + gpgme_data_t plain, gpgme_data_t sig, + gpgme_sig_mode_t mode); + + +/* Verify. */ + +/* Flags used for the SUMMARY field in a gpgme_signature_t. */ +typedef enum + { + GPGME_SIGSUM_VALID = 0x0001, /* The signature is fully valid. */ + GPGME_SIGSUM_GREEN = 0x0002, /* The signature is good. */ + GPGME_SIGSUM_RED = 0x0004, /* The signature is bad. */ + GPGME_SIGSUM_KEY_REVOKED = 0x0010, /* One key has been revoked. */ + GPGME_SIGSUM_KEY_EXPIRED = 0x0020, /* One key has expired. */ + GPGME_SIGSUM_SIG_EXPIRED = 0x0040, /* The signature has expired. */ + GPGME_SIGSUM_KEY_MISSING = 0x0080, /* Can't verify: key missing. */ + GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ + GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ + GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ + GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */ + } +gpgme_sigsum_t; + +struct _gpgme_signature +{ + struct _gpgme_signature *next; + + /* A summary of the signature status. */ + gpgme_sigsum_t summary; + + /* The fingerprint or key ID of the signature. */ + char *fpr; + + /* The status of the signature. */ + gpgme_error_t status; + + /* Notation data and policy URLs. */ + gpgme_sig_notation_t notations; + + /* Signature creation time. */ + unsigned long timestamp; + + /* Signature exipration time or 0. */ + unsigned long exp_timestamp; + + /* Key should not have been used for signing. */ + unsigned int wrong_key_usage : 1; + + /* PKA status: 0 = not available, 1 = bad, 2 = okay, 3 = RFU. */ + unsigned int pka_trust : 2; + + /* Internal to GPGME, do not use. */ + int _unused : 29; + + gpgme_validity_t validity; + gpgme_error_t validity_reason; + + /* The public key algorithm used to create the signature. */ + gpgme_pubkey_algo_t pubkey_algo; + + /* The hash algorithm used to create the signature. */ + gpgme_hash_algo_t hash_algo; + + /* The mailbox from the PKA information or NULL. */ + char *pka_address; +}; +typedef struct _gpgme_signature *gpgme_signature_t; + +struct _gpgme_op_verify_result +{ + gpgme_signature_t signatures; + + /* The original file name of the plaintext message, if + available. */ + char *file_name; +}; +typedef struct _gpgme_op_verify_result *gpgme_verify_result_t; + +/* Retrieve a pointer to the result of the verify operation. */ +gpgme_verify_result_t gpgme_op_verify_result (gpgme_ctx_t ctx); + +/* Verify within CTX that SIG is a valid signature for TEXT. */ +gpgme_error_t gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig, + gpgme_data_t signed_text, + gpgme_data_t plaintext); +gpgme_error_t gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, + gpgme_data_t signed_text, + gpgme_data_t plaintext); + + +/* Import. */ + +/* The key was new. */ +#define GPGME_IMPORT_NEW 1 + +/* The key contained new user IDs. */ +#define GPGME_IMPORT_UID 2 + +/* The key contained new signatures. */ +#define GPGME_IMPORT_SIG 4 + +/* The key contained new sub keys. */ +#define GPGME_IMPORT_SUBKEY 8 + +/* The key contained a secret key. */ +#define GPGME_IMPORT_SECRET 16 + + +struct _gpgme_import_status +{ + struct _gpgme_import_status *next; + + /* Fingerprint. */ + char *fpr; + + /* If a problem occured, the reason why the key could not be + imported. Otherwise GPGME_No_Error. */ + gpgme_error_t result; + + /* The result of the import, the GPGME_IMPORT_* values bit-wise + ORed. 0 means the key was already known and no new components + have been added. */ + unsigned int status; +}; +typedef struct _gpgme_import_status *gpgme_import_status_t; + +/* Import. */ +struct _gpgme_op_import_result +{ + /* Number of considered keys. */ + int considered; + + /* Keys without user ID. */ + int no_user_id; + + /* Imported keys. */ + int imported; + + /* Imported RSA keys. */ + int imported_rsa; + + /* Unchanged keys. */ + int unchanged; + + /* Number of new user ids. */ + int new_user_ids; + + /* Number of new sub keys. */ + int new_sub_keys; + + /* Number of new signatures. */ + int new_signatures; + + /* Number of new revocations. */ + int new_revocations; + + /* Number of secret keys read. */ + int secret_read; + + /* Number of secret keys imported. */ + int secret_imported; + + /* Number of secret keys unchanged. */ + int secret_unchanged; + + /* Number of new keys skipped. */ + int skipped_new_keys; + + /* Number of keys not imported. */ + int not_imported; + + /* List of keys for which an import was attempted. */ + gpgme_import_status_t imports; +}; +typedef struct _gpgme_op_import_result *gpgme_import_result_t; + +/* Retrieve a pointer to the result of the import operation. */ +gpgme_import_result_t gpgme_op_import_result (gpgme_ctx_t ctx); + +/* Import the key in KEYDATA into the keyring. */ +gpgme_error_t gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata); +gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata); +gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, + int *nr) _GPGME_DEPRECATED; + + +/* Export the keys found by PATTERN into KEYDATA. */ +gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, + unsigned int reserved, + gpgme_data_t keydata); +gpgme_error_t gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, + unsigned int reserved, gpgme_data_t keydata); + +gpgme_error_t gpgme_op_export_ext_start (gpgme_ctx_t ctx, + const char *pattern[], + unsigned int reserved, + gpgme_data_t keydata); +gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], + unsigned int reserved, + gpgme_data_t keydata); + + +/* Key generation. */ +struct _gpgme_op_genkey_result +{ + /* A primary key was generated. */ + unsigned int primary : 1; + + /* A sub key was generated. */ + unsigned int sub : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 30; + + /* The fingerprint of the generated key. */ + char *fpr; +}; +typedef struct _gpgme_op_genkey_result *gpgme_genkey_result_t; + +/* Generate a new keypair and add it to the keyring. PUBKEY and + SECKEY should be null for now. PARMS specifies what keys should be + generated. */ +gpgme_error_t gpgme_op_genkey_start (gpgme_ctx_t ctx, const char *parms, + gpgme_data_t pubkey, gpgme_data_t seckey); +gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, + gpgme_data_t pubkey, gpgme_data_t seckey); + +/* Retrieve a pointer to the result of the genkey operation. */ +gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx); + + +/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret + keys are also deleted. */ +gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, + int allow_secret); +gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, + int allow_secret); + + +/* Edit the key KEY. Send status and command requests to FNC and + output of edit commands to OUT. */ +gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, + gpgme_data_t out); +gpgme_error_t gpgme_op_edit (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, + gpgme_data_t out); + +/* Edit the card for the key KEY. Send status and command requests to + FNC and output of edit commands to OUT. */ +gpgme_error_t gpgme_op_card_edit_start (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, + gpgme_data_t out); +gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key, + gpgme_edit_cb_t fnc, void *fnc_value, + gpgme_data_t out); + + +/* Key management functions. */ +struct _gpgme_op_keylist_result +{ + unsigned int truncated : 1; + + /* Internal to GPGME, do not use. */ + unsigned int _unused : 31; +}; +typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t; + +/* Retrieve a pointer to the result of the key listing operation. */ +gpgme_keylist_result_t gpgme_op_keylist_result (gpgme_ctx_t ctx); + +/* Start a keylist operation within CTX, searching for keys which + match PATTERN. If SECRET_ONLY is true, only secret keys are + returned. */ +gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, + int secret_only); +gpgme_error_t gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, + const char *pattern[], + int secret_only, int reserved); + +/* Return the next key from the keylist in R_KEY. */ +gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key); + +/* Terminate a pending keylist operation within CTX. */ +gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx); + + +/* Trust items and operations. */ + +struct _gpgme_trust_item +{ + /* Internal to GPGME, do not use. */ + unsigned int _refs; + + /* The key ID to which the trust item belongs. */ + char *keyid; + + /* Internal to GPGME, do not use. */ + char _keyid[16 + 1]; + + /* The type of the trust item, 1 refers to a key, 2 to a user ID. */ + int type; + + /* The trust level. */ + int level; + + /* The owner trust if TYPE is 1. */ + char *owner_trust; + + /* Internal to GPGME, do not use. */ + char _owner_trust[2]; + + /* The calculated validity. */ + char *validity; + + /* Internal to GPGME, do not use. */ + char _validity[2]; + + /* The user name if TYPE is 2. */ + char *name; +}; +typedef struct _gpgme_trust_item *gpgme_trust_item_t; + +/* Start a trustlist operation within CTX, searching for trust items + which match PATTERN. */ +gpgme_error_t gpgme_op_trustlist_start (gpgme_ctx_t ctx, + const char *pattern, int max_level); + +/* Return the next trust item from the trustlist in R_ITEM. */ +gpgme_error_t gpgme_op_trustlist_next (gpgme_ctx_t ctx, + gpgme_trust_item_t *r_item); + +/* Terminate a pending trustlist operation within CTX. */ +gpgme_error_t gpgme_op_trustlist_end (gpgme_ctx_t ctx); + +/* Acquire a reference to ITEM. */ +void gpgme_trust_item_ref (gpgme_trust_item_t item); + +/* Release a reference to ITEM. If this was the last one the trust + item is destroyed. */ +void gpgme_trust_item_unref (gpgme_trust_item_t item); + +/* Release the trust item ITEM. Deprecated, use + gpgme_trust_item_unref. */ +void gpgme_trust_item_release (gpgme_trust_item_t item) _GPGME_DEPRECATED; + +/* Return the value of the attribute WHAT of ITEM, which has to be + representable by a string. Deprecated, use trust item structure + directly. */ +const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item, + _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + +/* Return the value of the attribute WHAT of KEY, which has to be + representable by an integer. IDX specifies a running index if the + attribute appears more than once in the key. Deprecated, use trust + item structure directly. */ +int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what, + const void *reserved, int idx) + _GPGME_DEPRECATED; + + +/* Various functions. */ + +/* Check that the library fulfills the version requirement. */ +const char *gpgme_check_version (const char *req_version); + +/* Get the information about the configured and installed engines. A + pointer to the first engine in the statically allocated linked list + is returned in *INFO. If an error occurs, it is returned. The + returned data is valid until the next gpgme_set_engine_info. */ +gpgme_error_t gpgme_get_engine_info (gpgme_engine_info_t *engine_info); + +/* Set the default engine info for the protocol PROTO to the file name + FILE_NAME and the home directory HOME_DIR. */ +gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto, + const char *file_name, + const char *home_dir); + + +/* Engine support functions. */ + +/* Verify that the engine implementing PROTO is installed and + available. */ +gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto); + + +/* Deprecated types. */ +typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED; +typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED; +typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED; +typedef gpgme_data_encoding_t GpgmeDataEncoding _GPGME_DEPRECATED; +typedef gpgme_pubkey_algo_t GpgmePubKeyAlgo _GPGME_DEPRECATED; +typedef gpgme_hash_algo_t GpgmeHashAlgo _GPGME_DEPRECATED; +typedef gpgme_sig_stat_t GpgmeSigStat _GPGME_DEPRECATED; +typedef gpgme_sig_mode_t GpgmeSigMode _GPGME_DEPRECATED; +typedef gpgme_attr_t GpgmeAttr _GPGME_DEPRECATED; +typedef gpgme_validity_t GpgmeValidity _GPGME_DEPRECATED; +typedef gpgme_protocol_t GpgmeProtocol _GPGME_DEPRECATED; +typedef gpgme_engine_info_t GpgmeEngineInfo _GPGME_DEPRECATED; +typedef gpgme_subkey_t GpgmeSubkey _GPGME_DEPRECATED; +typedef gpgme_key_sig_t GpgmeKeySig _GPGME_DEPRECATED; +typedef gpgme_user_id_t GpgmeUserID _GPGME_DEPRECATED; +typedef gpgme_key_t GpgmeKey _GPGME_DEPRECATED; +typedef gpgme_passphrase_cb_t GpgmePassphraseCb _GPGME_DEPRECATED; +typedef gpgme_progress_cb_t GpgmeProgressCb _GPGME_DEPRECATED; +typedef gpgme_io_cb_t GpgmeIOCb _GPGME_DEPRECATED; +typedef gpgme_register_io_cb_t GpgmeRegisterIOCb _GPGME_DEPRECATED; +typedef gpgme_remove_io_cb_t GpgmeRemoveIOCb _GPGME_DEPRECATED; +typedef gpgme_event_io_t GpgmeEventIO _GPGME_DEPRECATED; +typedef gpgme_event_io_cb_t GpgmeEventIOCb _GPGME_DEPRECATED; +#define GpgmeIOCbs gpgme_io_cbs +typedef gpgme_data_read_cb_t GpgmeDataReadCb _GPGME_DEPRECATED; +typedef gpgme_data_write_cb_t GpgmeDataWriteCb _GPGME_DEPRECATED; +typedef gpgme_data_seek_cb_t GpgmeDataSeekCb _GPGME_DEPRECATED; +typedef gpgme_data_release_cb_t GpgmeDataReleaseCb _GPGME_DEPRECATED; +#define GpgmeDataCbs gpgme_data_cbs +typedef gpgme_encrypt_result_t GpgmeEncryptResult _GPGME_DEPRECATED; +typedef gpgme_sig_notation_t GpgmeSigNotation _GPGME_DEPRECATED; +typedef gpgme_signature_t GpgmeSignature _GPGME_DEPRECATED; +typedef gpgme_verify_result_t GpgmeVerifyResult _GPGME_DEPRECATED; +typedef gpgme_import_status_t GpgmeImportStatus _GPGME_DEPRECATED; +typedef gpgme_import_result_t GpgmeImportResult _GPGME_DEPRECATED; +typedef gpgme_genkey_result_t GpgmeGenKeyResult _GPGME_DEPRECATED; +typedef gpgme_trust_item_t GpgmeTrustItem _GPGME_DEPRECATED; +typedef gpgme_status_code_t GpgmeStatusCode _GPGME_DEPRECATED; + +#ifdef __cplusplus +} +#endif +#endif /* GPGME_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/import.c b/libkdenetwork/libgpgme-copy/gpgme/import.c new file mode 100644 index 000000000..ad6b776bb --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/import.c @@ -0,0 +1,273 @@ +/* import.c - Import a key. + 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 <errno.h> +#include <string.h> + +#include "gpgme.h" +#include "context.h" +#include "ops.h" + + +typedef struct +{ + struct _gpgme_op_import_result result; + + /* A pointer to the next pointer of the last import status in the + list. This makes appending new imports painless while preserving + the order. */ + gpgme_import_status_t *lastp; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_import_status_t import = opd->result.imports; + + while (import) + { + gpgme_import_status_t next = import->next; + free (import->fpr); + free (import); + import = next; + } +} + + +gpgme_import_result_t +gpgme_op_import_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +static gpgme_error_t +parse_import (char *args, gpgme_import_status_t *import_status, int problem) +{ + gpgme_import_status_t import; + char *tail; + long int nr; + + import = malloc (sizeof (*import)); + if (!import) + return gpg_error_from_errno (errno); + import->next = NULL; + + errno = 0; + nr = strtol (args, &tail, 0); + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (import); + return gpg_error (GPG_ERR_INV_ENGINE); + } + args = tail; + + if (problem) + { + switch (nr) + { + case 0: + case 4: + default: + import->result = gpg_error (GPG_ERR_GENERAL); + break; + + case 1: + import->result = gpg_error (GPG_ERR_BAD_CERT); + break; + + case 2: + import->result = gpg_error (GPG_ERR_MISSING_CERT); + break; + + case 3: + import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN); + break; + } + import->status = 0; + } + else + { + import->result = gpg_error (GPG_ERR_NO_ERROR); + import->status = nr; + } + + while (*args == ' ') + args++; + tail = strchr (args, ' '); + if (tail) + *tail = '\0'; + + import->fpr = strdup (args); + if (!import->fpr) + { + int saved_errno = errno; + free (import); + return gpg_error_from_errno (saved_errno); + } + + *import_status = import; + return 0; +} + + + +gpgme_error_t +parse_import_res (char *args, gpgme_import_result_t result) +{ + char *tail; + + errno = 0; + +#define PARSE_NEXT(x) \ + (x) = strtol (args, &tail, 0); \ + if (errno || args == tail || *tail != ' ') \ + /* The crypto backend does not behave. */ \ + return gpg_error (GPG_ERR_INV_ENGINE); \ + args = tail; + + PARSE_NEXT (result->considered); + PARSE_NEXT (result->no_user_id); + PARSE_NEXT (result->imported); + PARSE_NEXT (result->imported_rsa); + PARSE_NEXT (result->unchanged); + PARSE_NEXT (result->new_user_ids); + PARSE_NEXT (result->new_sub_keys); + PARSE_NEXT (result->new_signatures); + PARSE_NEXT (result->new_revocations); + PARSE_NEXT (result->secret_read); + PARSE_NEXT (result->secret_imported); + PARSE_NEXT (result->secret_unchanged); + PARSE_NEXT (result->skipped_new_keys); + PARSE_NEXT (result->not_imported); + + return 0; +} + + +static gpgme_error_t +import_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_IMPORT_OK: + case GPGME_STATUS_IMPORT_PROBLEM: + err = parse_import (args, opd->lastp, + code == GPGME_STATUS_IMPORT_OK ? 0 : 1); + if (err) + return err; + + opd->lastp = &(*opd->lastp)->next; + break; + + case GPGME_STATUS_IMPORT_RES: + err = parse_import_res (args, &opd->result); + break; + + default: + break; + } + return 0; +} + + +static gpgme_error_t +_gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + opd->lastp = &opd->result.imports; + + if (!keydata) + return gpg_error (GPG_ERR_NO_DATA); + + _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); + + return _gpgme_engine_op_import (ctx->engine, keydata); +} + + +gpgme_error_t +gpgme_op_import_start (gpgme_ctx_t ctx, gpgme_data_t keydata) +{ + return _gpgme_op_import_start (ctx, 0, keydata); +} + + +/* Import the key in KEYDATA into the keyring. */ +gpgme_error_t +gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata) +{ + gpgme_error_t err = _gpgme_op_import_start (ctx, 1, keydata); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +gpgme_error_t +gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr) +{ + gpgme_error_t err = gpgme_op_import (ctx, keydata); + if (!err && nr) + { + gpgme_import_result_t result = gpgme_op_import_result (ctx); + *nr = result->considered; + } + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/io.h b/libkdenetwork/libgpgme-copy/gpgme/io.h new file mode 100644 index 000000000..47b748f8b --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/io.h @@ -0,0 +1,65 @@ +/* io.h - Interface to the I/O functions. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + GPGME is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GPGME; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef IO_H +#define IO_H + +/* A single file descriptor passed to spawn. For child fds, dup_to + specifies the fd it should become in the child. */ +struct spawn_fd_item_s +{ + int fd; + int dup_to; +}; + +struct io_select_fd_s +{ + int fd; + int for_read; + int for_write; + int signaled; + int frozen; + void *opaque; +}; + +/* These function are either defined in posix-io.c or w32-io.c. */ +void _gpgme_io_subsystem_init (void); +int _gpgme_io_read (int fd, void *buffer, size_t count); +int _gpgme_io_write (int fd, const void *buffer, size_t count); +int _gpgme_io_pipe (int filedes[2], int inherit_idx); +int _gpgme_io_close (int fd); +int _gpgme_io_set_close_notify (int fd, void (*handler) (int, void *), + void *value); +int _gpgme_io_set_nonblocking (int fd); + +/* Spawn the executable PATH with ARGV as arguments, after forking + close all fds in FD_PARENT_LIST in the parent and close or dup all + fds in FD_CHILD_LIST in the child. */ +int _gpgme_io_spawn (const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list); +int _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal); +int _gpgme_io_kill (int pid, int hard); +int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock); + +#endif /* IO_H */ + + + diff --git a/libkdenetwork/libgpgme-copy/gpgme/isascii.c b/libkdenetwork/libgpgme-copy/gpgme/isascii.c new file mode 100644 index 000000000..924ced0c6 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/isascii.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1991,92,93,95,96,97,98,99,2001,2002,2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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. + + The GNU C Library 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 the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +int +isascii (int c) +{ + return (((c) & ~0x7f) == 0); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/key.c b/libkdenetwork/libgpgme-copy/gpgme/key.c new file mode 100644 index 000000000..3dde670f0 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/key.c @@ -0,0 +1,722 @@ +/* key.c - Key objects. + 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 <assert.h> +#include <errno.h> + +#include "util.h" +#include "ops.h" +#include "sema.h" + + +/* Protects all reference counters in keys. All other accesses to a + key are read only. */ +DEFINE_STATIC_LOCK (key_ref_lock); + + +/* Create a new key. */ +gpgme_error_t +_gpgme_key_new (gpgme_key_t *r_key) +{ + gpgme_key_t key; + + key = calloc (1, sizeof *key); + if (!key) + return gpg_error_from_errno (errno); + key->_refs = 1; + + *r_key = key; + return 0; +} + + +gpgme_error_t +_gpgme_key_add_subkey (gpgme_key_t key, gpgme_subkey_t *r_subkey) +{ + gpgme_subkey_t subkey; + + subkey = calloc (1, sizeof *subkey); + if (!subkey) + return gpg_error_from_errno (errno); + subkey->keyid = subkey->_keyid; + subkey->_keyid[16] = '\0'; + + if (!key->subkeys) + key->subkeys = subkey; + if (key->_last_subkey) + key->_last_subkey->next = subkey; + key->_last_subkey = subkey; + + *r_subkey = subkey; + return 0; +} + + +static char * +set_user_id_part (char *tail, const char *buf, size_t len) +{ + while (len && (buf[len - 1] == ' ' || buf[len - 1] == '\t')) + len--; + for (; len; len--) + *tail++ = *buf++; + *tail++ = 0; + return tail; +} + + +static void +parse_user_id (char *src, char **name, char **email, + char **comment, char *tail) +{ + const char *start = NULL; + int in_name = 0; + int in_email = 0; + int in_comment = 0; + + while (*src) + { + if (in_email) + { + if (*src == '<') + /* Not legal but anyway. */ + in_email++; + else if (*src == '>') + { + if (!--in_email && !*email) + { + *email = tail; + tail = set_user_id_part (tail, start, src - start); + } + } + } + else if (in_comment) + { + if (*src == '(') + in_comment++; + else if (*src == ')') + { + if (!--in_comment && !*comment) + { + *comment = tail; + tail = set_user_id_part (tail, start, src - start); + } + } + } + else if (*src == '<') + { + if (in_name) + { + if (!*name) + { + *name = tail; + tail = set_user_id_part (tail, start, src - start); + } + in_name = 0; + } + in_email = 1; + start = src + 1; + } + else if (*src == '(') + { + if (in_name) + { + if (!*name) + { + *name = tail; + tail = set_user_id_part (tail, start, src - start); + } + in_name = 0; + } + in_comment = 1; + start = src + 1; + } + else if (!in_name && *src != ' ' && *src != '\t') + { + in_name = 1; + start = src; + } + src++; + } + + if (in_name) + { + if (!*name) + { + *name = tail; + tail = set_user_id_part (tail, start, src - start); + } + } + + /* Let unused parts point to an EOS. */ + tail--; + if (!*name) + *name = tail; + if (!*email) + *email = tail; + if (!*comment) + *comment = tail; +} + + +static void +parse_x509_user_id (char *src, char **name, char **email, + char **comment, char *tail) +{ + if (*src == '<' && src[strlen (src) - 1] == '>') + *email = src; + + /* Let unused parts point to an EOS. */ + tail--; + if (!*name) + *name = tail; + if (!*email) + *email = tail; + if (!*comment) + *comment = tail; +} + + +/* Take a name from the --with-colon listing, remove certain escape + sequences sequences and put it into the list of UIDs. */ +gpgme_error_t +_gpgme_key_append_name (gpgme_key_t key, char *src) +{ + gpgme_user_id_t uid; + char *dst; + int src_len = strlen (src); + + assert (key); + /* We can malloc a buffer of the same length, because the converted + string will never be larger. Actually we allocate it twice the + size, so that we are able to store the parsed stuff there too. */ + uid = malloc (sizeof (*uid) + 2 * src_len + 3); + if (!uid) + return gpg_error_from_errno (errno); + memset (uid, 0, sizeof *uid); + + uid->uid = ((char *) uid) + sizeof (*uid); + dst = uid->uid; + _gpgme_decode_c_string (src, &dst, src_len + 1); + + dst += strlen (dst) + 1; + if (key->protocol == GPGME_PROTOCOL_CMS) + parse_x509_user_id (uid->uid, &uid->name, &uid->email, + &uid->comment, dst); + else + parse_user_id (uid->uid, &uid->name, &uid->email, + &uid->comment, dst); + + if (!key->uids) + key->uids = uid; + if (key->_last_uid) + key->_last_uid->next = uid; + key->_last_uid = uid; + + return 0; +} + + +gpgme_key_sig_t +_gpgme_key_add_sig (gpgme_key_t key, char *src) +{ + int src_len = src ? strlen (src) : 0; + gpgme_user_id_t uid; + gpgme_key_sig_t sig; + + assert (key); /* XXX */ + + uid = key->_last_uid; + assert (uid); /* XXX */ + + /* We can malloc a buffer of the same length, because the converted + string will never be larger. Actually we allocate it twice the + size, so that we are able to store the parsed stuff there too. */ + sig = malloc (sizeof (*sig) + 2 * src_len + 3); + if (!sig) + return NULL; + memset (sig, 0, sizeof *sig); + + sig->keyid = sig->_keyid; + sig->_keyid[16] = '\0'; + sig->uid = ((char *) sig) + sizeof (*sig); + + if (src) + { + char *dst = sig->uid; + _gpgme_decode_c_string (src, &dst, src_len + 1); + dst += strlen (dst) + 1; + if (key->protocol == GPGME_PROTOCOL_CMS) + parse_x509_user_id (sig->uid, &sig->name, &sig->email, + &sig->comment, dst); + else + parse_user_id (sig->uid, &sig->name, &sig->email, + &sig->comment, dst); + } + + if (!uid->signatures) + uid->signatures = sig; + if (uid->_last_keysig) + uid->_last_keysig->next = sig; + uid->_last_keysig = sig; + + return sig; +} + + +/* Acquire a reference to KEY. */ +void +gpgme_key_ref (gpgme_key_t key) +{ + LOCK (key_ref_lock); + key->_refs++; + UNLOCK (key_ref_lock); +} + + +/* gpgme_key_unref releases the key object. Note, that this function + may not do an actual release if there are other shallow copies of + the objects. You have to call this function for every newly + created key object as well as for every gpgme_key_ref() done on the + key object. */ +void +gpgme_key_unref (gpgme_key_t key) +{ + gpgme_user_id_t uid; + gpgme_subkey_t subkey; + + if (!key) + return; + + LOCK (key_ref_lock); + assert (key->_refs > 0); + if (--key->_refs) + { + UNLOCK (key_ref_lock); + return; + } + UNLOCK (key_ref_lock); + + subkey = key->subkeys; + while (subkey) + { + gpgme_subkey_t next = subkey->next; + if (subkey->fpr) + free (subkey->fpr); + free (subkey); + subkey = next; + } + + uid = key->uids; + while (uid) + { + gpgme_user_id_t next_uid = uid->next; + gpgme_key_sig_t keysig = uid->signatures; + + while (keysig) + { + gpgme_key_sig_t next_keysig = keysig->next; + gpgme_sig_notation_t notation = keysig->notations; + + while (notation) + { + gpgme_sig_notation_t next_notation = notation->next; + + _gpgme_sig_notation_free (notation); + notation = next_notation; + } + + free (keysig); + keysig = next_keysig; + } + free (uid); + uid = next_uid; + } + + if (key->issuer_serial) + free (key->issuer_serial); + if (key->issuer_name) + free (key->issuer_name); + + if (key->chain_id) + free (key->chain_id); + + free (key); +} + + +/* Compatibility interfaces. */ + +void +gpgme_key_release (gpgme_key_t key) +{ + gpgme_key_unref (key); +} + + +static const char * +otrust_to_string (int otrust) +{ + switch (otrust) + { + case GPGME_VALIDITY_NEVER: + return "n"; + + case GPGME_VALIDITY_MARGINAL: + return "m"; + + case GPGME_VALIDITY_FULL: + return "f"; + + case GPGME_VALIDITY_ULTIMATE: + return "u"; + + default: + return "?"; + } +} + + +static const char * +validity_to_string (int validity) +{ + switch (validity) + { + case GPGME_VALIDITY_UNDEFINED: + return "q"; + + case GPGME_VALIDITY_NEVER: + return "n"; + + case GPGME_VALIDITY_MARGINAL: + return "m"; + + case GPGME_VALIDITY_FULL: + return "f"; + + case GPGME_VALIDITY_ULTIMATE: + return "u"; + + case GPGME_VALIDITY_UNKNOWN: + default: + return "?"; + } +} + + +static const char * +capabilities_to_string (gpgme_subkey_t subkey) +{ + static const char *const strings[8] = + { + "", + "c", + "s", + "sc", + "e", + "ec", + "es", + "esc" + }; + return strings[(!!subkey->can_encrypt << 2) + | (!!subkey->can_sign << 1) + | (!!subkey->can_certify)]; +} + + +/* Return the value of the attribute WHAT of ITEM, which has to be + representable by a string. */ +const char * +gpgme_key_get_string_attr (gpgme_key_t key, _gpgme_attr_t what, + const void *reserved, int idx) +{ + gpgme_subkey_t subkey; + gpgme_user_id_t uid; + int i; + + if (!key || reserved || idx < 0) + return NULL; + + /* Select IDXth subkey. */ + subkey = key->subkeys; + for (i = 0; i < idx; i++) + { + subkey = subkey->next; + if (!subkey) + break; + } + + /* Select the IDXth user ID. */ + uid = key->uids; + for (i = 0; i < idx; i++) + { + uid = uid->next; + if (!uid) + break; + } + + switch (what) + { + case GPGME_ATTR_KEYID: + return subkey ? subkey->keyid : NULL; + + case GPGME_ATTR_FPR: + return subkey ? subkey->fpr : NULL; + + case GPGME_ATTR_ALGO: + return subkey ? gpgme_pubkey_algo_name (subkey->pubkey_algo) : NULL; + + case GPGME_ATTR_TYPE: + return key->protocol == GPGME_PROTOCOL_CMS ? "X.509" : "PGP"; + + case GPGME_ATTR_OTRUST: + return otrust_to_string (key->owner_trust); + + case GPGME_ATTR_USERID: + return uid ? uid->uid : NULL; + + case GPGME_ATTR_NAME: + return uid ? uid->name : NULL; + + case GPGME_ATTR_EMAIL: + return uid ? uid->email : NULL; + + case GPGME_ATTR_COMMENT: + return uid ? uid->comment : NULL; + + case GPGME_ATTR_VALIDITY: + return uid ? validity_to_string (uid->validity) : NULL; + + case GPGME_ATTR_KEY_CAPS: + return subkey ? capabilities_to_string (subkey) : NULL; + + case GPGME_ATTR_SERIAL: + return key->issuer_serial; + + case GPGME_ATTR_ISSUER: + return idx ? NULL : key->issuer_name; + + case GPGME_ATTR_CHAINID: + return key->chain_id; + + default: + return NULL; + } +} + + +unsigned long +gpgme_key_get_ulong_attr (gpgme_key_t key, _gpgme_attr_t what, + const void *reserved, int idx) +{ + gpgme_subkey_t subkey; + gpgme_user_id_t uid; + int i; + + if (!key || reserved || idx < 0) + return 0; + + /* Select IDXth subkey. */ + subkey = key->subkeys; + for (i = 0; i < idx; i++) + { + subkey = subkey->next; + if (!subkey) + break; + } + + /* Select the IDXth user ID. */ + uid = key->uids; + for (i = 0; i < idx; i++) + { + uid = uid->next; + if (!uid) + break; + } + + switch (what) + { + case GPGME_ATTR_ALGO: + return subkey ? (unsigned long) subkey->pubkey_algo : 0; + + case GPGME_ATTR_LEN: + return subkey ? (unsigned long) subkey->length : 0; + + case GPGME_ATTR_TYPE: + return key->protocol == GPGME_PROTOCOL_CMS ? 1 : 0; + + case GPGME_ATTR_CREATED: + return (subkey && subkey->timestamp >= 0) + ? (unsigned long) subkey->timestamp : 0; + + case GPGME_ATTR_EXPIRE: + return (subkey && subkey->expires >= 0) + ? (unsigned long) subkey->expires : 0; + + case GPGME_ATTR_VALIDITY: + return uid ? uid->validity : 0; + + case GPGME_ATTR_OTRUST: + return key->owner_trust; + + case GPGME_ATTR_IS_SECRET: + return !!key->secret; + + case GPGME_ATTR_KEY_REVOKED: + return subkey ? subkey->revoked : 0; + + case GPGME_ATTR_KEY_INVALID: + return subkey ? subkey->invalid : 0; + + case GPGME_ATTR_KEY_EXPIRED: + return subkey ? subkey->expired : 0; + + case GPGME_ATTR_KEY_DISABLED: + return subkey ? subkey->disabled : 0; + + case GPGME_ATTR_UID_REVOKED: + return uid ? uid->revoked : 0; + + case GPGME_ATTR_UID_INVALID: + return uid ? uid->invalid : 0; + + case GPGME_ATTR_CAN_ENCRYPT: + return key->can_encrypt; + + case GPGME_ATTR_CAN_SIGN: + return key->can_sign; + + case GPGME_ATTR_CAN_CERTIFY: + return key->can_certify; + + default: + return 0; + } +} + + +static gpgme_key_sig_t +get_keysig (gpgme_key_t key, int uid_idx, int idx) +{ + gpgme_user_id_t uid; + gpgme_key_sig_t sig; + + if (!key || uid_idx < 0 || idx < 0) + return NULL; + + uid = key->uids; + while (uid && uid_idx > 0) + { + uid = uid->next; + uid_idx--; + } + if (!uid) + return NULL; + + sig = uid->signatures; + while (sig && idx > 0) + { + sig = sig->next; + idx--; + } + return sig; +} + + +const char * +gpgme_key_sig_get_string_attr (gpgme_key_t key, int uid_idx, + _gpgme_attr_t what, + const void *reserved, int idx) +{ + gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx); + + if (!certsig || reserved) + return NULL; + + switch (what) + { + case GPGME_ATTR_KEYID: + return certsig->keyid; + + case GPGME_ATTR_ALGO: + return gpgme_pubkey_algo_name (certsig->pubkey_algo); + + case GPGME_ATTR_USERID: + return certsig->uid; + + case GPGME_ATTR_NAME: + return certsig->name; + + case GPGME_ATTR_EMAIL: + return certsig->email; + + case GPGME_ATTR_COMMENT: + return certsig->comment; + + default: + return NULL; + } +} + + +unsigned long +gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, _gpgme_attr_t what, + const void *reserved, int idx) +{ + gpgme_key_sig_t certsig = get_keysig (key, uid_idx, idx); + + if (!certsig || reserved) + return 0; + + switch (what) + { + case GPGME_ATTR_ALGO: + return (unsigned long) certsig->pubkey_algo; + + case GPGME_ATTR_CREATED: + return certsig->timestamp < 0 ? 0L : (unsigned long) certsig->timestamp; + + case GPGME_ATTR_EXPIRE: + return certsig->expires < 0 ? 0L : (unsigned long) certsig->expires; + + case GPGME_ATTR_KEY_REVOKED: + return certsig->revoked; + + case GPGME_ATTR_KEY_INVALID: + return certsig->invalid; + + case GPGME_ATTR_KEY_EXPIRED: + return certsig->expired; + + case GPGME_ATTR_SIG_CLASS: + return certsig->sig_class; + + case GPGME_ATTR_SIG_STATUS: + return certsig->status; + + default: + return 0; + } +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/keylist.c b/libkdenetwork/libgpgme-copy/gpgme/keylist.c new file mode 100644 index 000000000..1c60da5cf --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/keylist.c @@ -0,0 +1,980 @@ +/* keylist.c - Listing keys. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2006 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> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <assert.h> +#include <ctype.h> +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "context.h" +#include "ops.h" +#include "debug.h" + + +struct key_queue_item_s +{ + struct key_queue_item_s *next; + gpgme_key_t key; +}; + +typedef struct +{ + struct _gpgme_op_keylist_result result; + + gpgme_key_t tmp_key; + + /* This points to the last uid in tmp_key. */ + gpgme_user_id_t tmp_uid; + + /* This points to the last sig in tmp_uid. */ + gpgme_key_sig_t tmp_keysig; + + /* Something new is available. */ + int key_cond; + struct key_queue_item_s *key_queue; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + struct key_queue_item_s *key = opd->key_queue; + + if (opd->tmp_key) + gpgme_key_unref (opd->tmp_key); + + /* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key, + so we do not need to release them here. */ + + while (key) + { + struct key_queue_item_s *next = key->next; + + gpgme_key_unref (key->key); + key = next; + } +} + + +gpgme_keylist_result_t +gpgme_op_keylist_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +static gpgme_error_t +keylist_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_TRUNCATED: + opd->result.truncated = 1; + break; + + default: + break; + } + return 0; +} + + +static void +set_subkey_trust_info (gpgme_subkey_t subkey, const char *src) +{ + while (*src && !isdigit (*src)) + { + switch (*src) + { + case 'e': + subkey->expired = 1; + break; + + case 'r': + subkey->revoked = 1; + break; + + case 'd': + /* Note that gpg 1.3 won't print that anymore but only uses + the capabilities field. */ + subkey->disabled = 1; + break; + + case 'i': + subkey->invalid = 1; + break; + } + src++; + } +} + + +static void +set_mainkey_trust_info (gpgme_key_t key, const char *src) +{ + /* First set the trust info of the main key (the first subkey). */ + set_subkey_trust_info (key->subkeys, src); + + /* Now set the summarized trust info. */ + while (*src && !isdigit (*src)) + { + switch (*src) + { + case 'e': + key->expired = 1; + break; + + case 'r': + key->revoked = 1; + break; + + case 'd': + /* Note that gpg 1.3 won't print that anymore but only uses + the capabilities field. However, it is still used for + external key listings. */ + key->disabled = 1; + break; + + case 'i': + key->invalid = 1; + break; + } + src++; + } +} + + +static void +set_userid_flags (gpgme_key_t key, const char *src) +{ + gpgme_user_id_t uid = key->_last_uid; + + assert (uid); + /* Look at letters and stop at the first digit. */ + while (*src && !isdigit (*src)) + { + switch (*src) + { + case 'r': + uid->revoked = 1; + break; + + case 'i': + uid->invalid = 1; + break; + + case 'n': + uid->validity = GPGME_VALIDITY_NEVER; + break; + + case 'm': + uid->validity = GPGME_VALIDITY_MARGINAL; + break; + + case 'f': + uid->validity = GPGME_VALIDITY_FULL; + break; + + case 'u': + uid->validity = GPGME_VALIDITY_ULTIMATE; + break; + } + src++; + } +} + + +static void +set_subkey_capability (gpgme_subkey_t subkey, const char *src) +{ + while (*src) + { + switch (*src) + { + case 'e': + subkey->can_encrypt = 1; + break; + + case 's': + subkey->can_sign = 1; + break; + + case 'c': + subkey->can_certify = 1; + break; + + case 'a': + subkey->can_authenticate = 1; + break; + + case 'q': + subkey->is_qualified = 1; + break; + + case 'd': + subkey->disabled = 1; + break; + } + src++; + } +} + + +static void +set_mainkey_capability (gpgme_key_t key, const char *src) +{ + /* First set the capabilities of the main key (the first subkey). */ + set_subkey_capability (key->subkeys, src); + + while (*src) + { + switch (*src) + { + case 'd': + case 'D': + /* Note, that this flag is also set using the key validity + field for backward compatibility with gpg 1.2. We use d + and D, so that a future gpg version will be able to + disable certain subkeys. Currently it is expected that + gpg sets this for the primary key. */ + key->disabled = 1; + break; + + case 'e': + case 'E': + key->can_encrypt = 1; + break; + + case 's': + case 'S': + key->can_sign = 1; + break; + + case 'c': + case 'C': + key->can_certify = 1; + break; + + case 'a': + case 'A': + key->can_authenticate = 1; + break; + + case 'q': + case 'Q': + key->is_qualified = 1; + break; + } + src++; + } +} + + +static void +set_ownertrust (gpgme_key_t key, const char *src) +{ + /* Look at letters and stop at the first digit. */ + while (*src && !isdigit (*src)) + { + switch (*src) + { + case 'n': + key->owner_trust = GPGME_VALIDITY_NEVER; + break; + + case 'm': + key->owner_trust = GPGME_VALIDITY_MARGINAL; + break; + + case 'f': + key->owner_trust = GPGME_VALIDITY_FULL; + break; + + case 'u': + key->owner_trust = GPGME_VALIDITY_ULTIMATE; + break; + + default: + key->owner_trust = GPGME_VALIDITY_UNKNOWN; + break; + } + src++; + } +} + + +/* We have read an entire key into tmp_key and should now finish it. + It is assumed that this releases tmp_key. */ +static void +finish_key (gpgme_ctx_t ctx, op_data_t opd) +{ + gpgme_key_t key = opd->tmp_key; + + opd->tmp_key = NULL; + opd->tmp_uid = NULL; + opd->tmp_keysig = NULL; + + if (key) + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key); +} + + +/* Note: We are allowed to modify LINE. */ +static gpgme_error_t +keylist_colon_handler (void *priv, char *line) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + enum + { + RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, + RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK + } + rectype = RT_NONE; +#define NR_FIELDS 16 + char *field[NR_FIELDS]; + int fields = 0; + void *hook; + op_data_t opd; + gpgme_error_t err; + gpgme_key_t key; + gpgme_subkey_t subkey = NULL; + gpgme_key_sig_t keysig = NULL; + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + key = opd->tmp_key; + + DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n", + ctx, key, line ? line : "(null)"); + + if (!line) + { + /* End Of File. */ + finish_key (ctx, opd); + return 0; + } + + while (line && fields < NR_FIELDS) + { + field[fields++] = line; + line = strchr (line, ':'); + if (line) + *(line++) = '\0'; + } + + if (!strcmp (field[0], "sig")) + rectype = RT_SIG; + else if (!strcmp (field[0], "rev")) + rectype = RT_REV; + else if (!strcmp (field[0], "pub")) + rectype = RT_PUB; + else if (!strcmp (field[0], "sec")) + rectype = RT_SEC; + else if (!strcmp (field[0], "crt")) + rectype = RT_CRT; + else if (!strcmp (field[0], "crs")) + rectype = RT_CRS; + else if (!strcmp (field[0], "fpr") && key) + rectype = RT_FPR; + else if (!strcmp (field[0], "uid") && key) + rectype = RT_UID; + else if (!strcmp (field[0], "sub") && key) + rectype = RT_SUB; + else if (!strcmp (field[0], "ssb") && key) + rectype = RT_SSB; + else if (!strcmp (field[0], "spk") && key) + rectype = RT_SPK; + else + rectype = RT_NONE; + + /* Only look at signatures immediately following a user ID. For + this, clear the user ID pointer when encountering anything but a + signature. */ + if (rectype != RT_SIG && rectype != RT_REV) + opd->tmp_uid = NULL; + + /* Only look at subpackets immediately following a signature. For + this, clear the signature pointer when encountering anything but + a subpacket. */ + if (rectype != RT_SPK) + opd->tmp_keysig = NULL; + + switch (rectype) + { + case RT_PUB: + case RT_SEC: + case RT_CRT: + case RT_CRS: + /* Start a new keyblock. */ + err = _gpgme_key_new (&key); + if (err) + return err; + key->keylist_mode = ctx->keylist_mode; + err = _gpgme_key_add_subkey (key, &subkey); + if (err) + { + gpgme_key_unref (key); + return err; + } + + if (rectype == RT_SEC || rectype == RT_CRS) + key->secret = subkey->secret = 1; + if (rectype == RT_CRT || rectype == RT_CRS) + key->protocol = GPGME_PROTOCOL_CMS; + finish_key (ctx, opd); + opd->tmp_key = key; + + /* Field 2 has the trust info. */ + if (fields >= 2) + set_mainkey_trust_info (key, field[1]); + + /* Field 3 has the key length. */ + if (fields >= 3) + { + int i = atoi (field[2]); + /* Ignore invalid values. */ + if (i > 1) + subkey->length = i; + } + + /* Field 4 has the public key algorithm. */ + if (fields >= 4) + { + int i = atoi (field[3]); + if (i >= 1 && i < 128) + subkey->pubkey_algo = i; + } + + /* Field 5 has the long keyid. Allow short key IDs for the + output of an external keyserver listing. */ + if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1) + strcpy (subkey->_keyid, field[4]); + + /* Field 6 has the timestamp (seconds). */ + if (fields >= 6) + subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL); + + /* Field 7 has the expiration time (seconds). */ + if (fields >= 7) + subkey->expires = _gpgme_parse_timestamp (field[6], NULL); + + /* Field 8 has the X.509 serial number. */ + if (fields >= 8 && (rectype == RT_CRT || rectype == RT_CRS)) + { + key->issuer_serial = strdup (field[7]); + if (!key->issuer_serial) + return gpg_error_from_errno (errno); + } + + /* Field 9 has the ownertrust. */ + if (fields >= 9) + set_ownertrust (key, field[8]); + + /* Field 10 is not used for gpg due to --fixed-list-mode option + but GPGSM stores the issuer name. */ + if (fields >= 10 && (rectype == RT_CRT || rectype == RT_CRS)) + if (_gpgme_decode_c_string (field[9], &key->issuer_name, 0)) + return gpg_error (GPG_ERR_ENOMEM); /* FIXME */ + + /* Field 11 has the signature class. */ + + /* Field 12 has the capabilities. */ + if (fields >= 12) + set_mainkey_capability (key, field[11]); + + /* Field 15 carries special flags of a secret key. We reset the + SECRET flag of a subkey here if the key is actually only a + stub. The SECRET flag of the key will be true even then. */ + if (fields >= 15 && key->secret) + if (*field[14] == '#') + subkey->secret = 0; + break; + + case RT_SUB: + case RT_SSB: + /* Start a new subkey. */ + err = _gpgme_key_add_subkey (key, &subkey); + if (err) + return err; + + if (rectype == RT_SSB) + subkey->secret = 1; + + /* Field 2 has the trust info. */ + if (fields >= 2) + set_subkey_trust_info (subkey, field[1]); + + /* Field 3 has the key length. */ + if (fields >= 3) + { + int i = atoi (field[2]); + /* Ignore invalid values. */ + if (i > 1) + subkey->length = i; + } + + /* Field 4 has the public key algorithm. */ + if (fields >= 4) + { + int i = atoi (field[3]); + if (i >= 1 && i < 128) + subkey->pubkey_algo = i; + } + + /* Field 5 has the long keyid. */ + if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1) + strcpy (subkey->_keyid, field[4]); + + /* Field 6 has the timestamp (seconds). */ + if (fields >= 6) + subkey->timestamp = _gpgme_parse_timestamp (field[5], NULL); + + /* Field 7 has the expiration time (seconds). */ + if (fields >= 7) + subkey->expires = _gpgme_parse_timestamp (field[6], NULL); + + /* Field 8 is reserved (LID). */ + /* Field 9 has the ownertrust. */ + /* Field 10, the user ID, is n/a for a subkey. */ + + /* Field 11 has the signature class. */ + + /* Field 12 has the capabilities. */ + if (fields >= 12) + set_subkey_capability (subkey, field[11]); + + /* Field 15 carries special flags of a secret key. */ + if (fields >= 15 && key->secret) + if (*field[14] == '#') + subkey->secret = 0; + break; + + case RT_UID: + /* Field 2 has the trust info, and field 10 has the user ID. */ + if (fields >= 10) + { + if (_gpgme_key_append_name (key, field[9])) + return gpg_error_from_errno (GPG_ERR_ENOMEM); /* FIXME */ + else + { + if (field[1]) + set_userid_flags (key, field[1]); + opd->tmp_uid = key->_last_uid; + } + } + break; + + case RT_FPR: + /* Field 10 has the fingerprint (take only the first one). */ + if (fields >= 10 && field[9] && *field[9]) + { + /* Need to apply it to the last subkey because all subkeys + do have fingerprints. */ + subkey = key->_last_subkey; + if (!subkey->fpr) + { + subkey->fpr = strdup (field[9]); + if (!subkey->fpr) + return gpg_error_from_errno (errno); + } + } + + /* Field 13 has the gpgsm chain ID (take only the first one). */ + if (fields >= 13 && !key->chain_id && *field[12]) + { + key->chain_id = strdup (field[12]); + if (!key->chain_id) + return gpg_error_from_errno (errno); + } + break; + + case RT_SIG: + case RT_REV: + if (!opd->tmp_uid) + return 0; + + /* Start a new (revoked) signature. */ + assert (opd->tmp_uid == key->_last_uid); + keysig = _gpgme_key_add_sig (key, (fields >= 10) ? field[9] : NULL); + if (!keysig) + return gpg_error (GPG_ERR_ENOMEM); /* FIXME */ + + /* Field 2 has the calculated trust ('!', '-', '?', '%'). */ + if (fields >= 2) + switch (field[1][0]) + { + case '!': + keysig->status = gpg_error (GPG_ERR_NO_ERROR); + break; + + case '-': + keysig->status = gpg_error (GPG_ERR_BAD_SIGNATURE); + break; + + case '?': + keysig->status = gpg_error (GPG_ERR_NO_PUBKEY); + break; + + case '%': + keysig->status = gpg_error (GPG_ERR_GENERAL); + break; + + default: + keysig->status = gpg_error (GPG_ERR_NO_ERROR); + break; + } + + /* Field 4 has the public key algorithm. */ + if (fields >= 4) + { + int i = atoi (field[3]); + if (i >= 1 && i < 128) + keysig->pubkey_algo = i; + } + + /* Field 5 has the long keyid. */ + if (fields >= 5 && strlen (field[4]) == DIM(keysig->_keyid) - 1) + strcpy (keysig->_keyid, field[4]); + + /* Field 6 has the timestamp (seconds). */ + if (fields >= 6) + keysig->timestamp = _gpgme_parse_timestamp (field[5], NULL); + + /* Field 7 has the expiration time (seconds). */ + if (fields >= 7) + keysig->expires = _gpgme_parse_timestamp (field[6], NULL); + + /* Field 11 has the signature class (eg, 0x30 means revoked). */ + if (fields >= 11) + if (field[10][0] && field[10][1]) + { + int sig_class = _gpgme_hextobyte (field[10]); + if (sig_class >= 0) + { + keysig->sig_class = sig_class; + keysig->class = keysig->sig_class; + if (sig_class == 0x30) + keysig->revoked = 1; + } + if (field[10][2] == 'x') + keysig->exportable = 1; + } + + opd->tmp_keysig = keysig; + break; + + case RT_SPK: + if (!opd->tmp_keysig) + return 0; + assert (opd->tmp_keysig == key->_last_uid->_last_keysig); + + if (fields >= 4) + { + /* Field 2 has the subpacket type. */ + int type = atoi (field[1]); + + /* Field 3 has the flags. */ + int flags = atoi (field[2]); + + /* Field 4 has the length. */ + int len = atoi (field[3]); + + /* Field 5 has the data. */ + char *data = field[4]; + + /* Type 20: Notation data. */ + /* Type 26: Policy URL. */ + if (type == 20 || type == 26) + { + gpgme_sig_notation_t notation; + + keysig = opd->tmp_keysig; + + /* At this time, any error is serious. */ + err = _gpgme_parse_notation (¬ation, type, flags, len, data); + if (err) + return err; + + /* Add a new notation. FIXME: Could be factored out. */ + if (!keysig->notations) + keysig->notations = notation; + if (keysig->_last_notation) + keysig->_last_notation->next = notation; + keysig->_last_notation = notation; + } + } + + case RT_NONE: + /* Unknown record. */ + break; + } + return 0; +} + + +void +_gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data) +{ + gpgme_error_t err; + gpgme_ctx_t ctx = (gpgme_ctx_t) data; + gpgme_key_t key = (gpgme_key_t) type_data; + void *hook; + op_data_t opd; + struct key_queue_item_s *q, *q2; + + assert (type == GPGME_EVENT_NEXT_KEY); + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL); + opd = hook; + if (err) + return; + + q = malloc (sizeof *q); + if (!q) + { + gpgme_key_unref (key); + /* FIXME return GPGME_Out_Of_Core; */ + return; + } + q->key = key; + q->next = NULL; + /* FIXME: Use a tail pointer? */ + if (!(q2 = opd->key_queue)) + opd->key_queue = q; + else + { + for (; q2->next; q2 = q2->next) + ; + q2->next = q; + } + opd->key_cond = 1; +} + + +/* Start a keylist operation within CTX, searching for keys which + match PATTERN. If SECRET_ONLY is true, only secret keys are + returned. */ +gpgme_error_t +gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_reset (ctx, 2); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx); + + err = _gpgme_engine_set_colon_line_handler (ctx->engine, + keylist_colon_handler, ctx); + if (err) + return err; + + return _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, + ctx->keylist_mode); +} + + +/* Start a keylist operation within CTX, searching for keys which + match PATTERN. If SECRET_ONLY is true, only secret keys are + returned. */ +gpgme_error_t +gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], + int secret_only, int reserved) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_reset (ctx, 2); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, keylist_status_handler, ctx); + err = _gpgme_engine_set_colon_line_handler (ctx->engine, + keylist_colon_handler, ctx); + if (err) + return err; + + return _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only, + reserved, ctx->keylist_mode); +} + + +/* Return the next key from the keylist in R_KEY. */ +gpgme_error_t +gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key) +{ + gpgme_error_t err; + struct key_queue_item_s *queue_item; + void *hook; + op_data_t opd; + + if (!ctx || !r_key) + return gpg_error (GPG_ERR_INV_VALUE); + *r_key = NULL; + if (!ctx) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL); + opd = hook; + if (err) + return err; + if (opd == NULL) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!opd->key_queue) + { + err = _gpgme_wait_on_condition (ctx, &opd->key_cond); + if (err) + return err; + + if (!opd->key_cond) + return gpg_error (GPG_ERR_EOF); + + opd->key_cond = 0; + assert (opd->key_queue); + } + queue_item = opd->key_queue; + opd->key_queue = queue_item->next; + if (!opd->key_queue) + opd->key_cond = 0; + + *r_key = queue_item->key; + free (queue_item); + return 0; +} + + +/* Terminate a pending keylist operation within CTX. */ +gpgme_error_t +gpgme_op_keylist_end (gpgme_ctx_t ctx) +{ + if (!ctx) + return gpg_error (GPG_ERR_INV_VALUE); + + return 0; +} + + +/* Get the key with the fingerprint FPR from the crypto backend. If + SECRET is true, get the secret key. */ +gpgme_error_t +gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key, + int secret) +{ + gpgme_ctx_t listctx; + gpgme_error_t err; + gpgme_key_t key; + + if (!ctx || !r_key || !fpr) + return gpg_error (GPG_ERR_INV_VALUE); + + if (strlen (fpr) < 8) /* We have at least a key ID. */ + return gpg_error (GPG_ERR_INV_VALUE); + + /* FIXME: We use our own context because we have to avoid the user's + I/O callback handlers. */ + err = gpgme_new (&listctx); + if (err) + return err; + { + gpgme_protocol_t proto; + gpgme_engine_info_t info; + + /* Clone the relevant state. */ + proto = gpgme_get_protocol (ctx); + gpgme_set_protocol (listctx, proto); + gpgme_set_keylist_mode (listctx, gpgme_get_keylist_mode (ctx)); + info = gpgme_ctx_get_engine_info (ctx); + while (info && info->protocol != proto) + info = info->next; + if (info) + gpgme_ctx_set_engine_info (listctx, proto, + info->file_name, info->home_dir); + } + + err = gpgme_op_keylist_start (listctx, fpr, secret); + if (!err) + err = gpgme_op_keylist_next (listctx, r_key); + if (!err) + { + err = gpgme_op_keylist_next (listctx, &key); + if (gpgme_err_code (err) == GPG_ERR_EOF) + err = gpg_error (GPG_ERR_NO_ERROR); + else + { + if (!err) + { + gpgme_key_unref (key); + err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); + } + gpgme_key_unref (*r_key); + } + } + gpgme_release (listctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/libgpgme.vers b/libkdenetwork/libgpgme-copy/gpgme/libgpgme.vers new file mode 100644 index 000000000..da90a7725 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/libgpgme.vers @@ -0,0 +1,167 @@ +# libgpgme.vers - List of symbols to export. +# 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 + +#------------------------------------------------------- +# Please remember to add new functions also to gpgme.def +#------------------------------------------------------- + +GPGME_1.1 { + global: + gpgme_set_engine_info; + + gpgme_ctx_get_engine_info; + gpgme_ctx_set_engine_info; + + gpgme_data_set_file_name; + gpgme_data_get_file_name; + + gpgme_sig_notation_clear; + gpgme_sig_notation_add; + gpgme_sig_notation_get; + + gpgme_free; +}; + + +GPGME_1.0 { + global: + gpgme_check_version; + gpgme_get_engine_info; + gpgme_engine_check_version; + + gpgme_err_code_from_errno; + gpgme_err_code_to_errno; + gpgme_err_make_from_errno; + gpgme_error_from_errno; + gpgme_strerror; + gpgme_strerror_r; + gpgme_strsource; + + gpgme_data_get_encoding; + gpgme_data_new; + gpgme_data_new_from_cbs; + gpgme_data_new_from_fd; + gpgme_data_new_from_file; + gpgme_data_new_from_filepart; + gpgme_data_new_from_mem; + gpgme_data_new_from_stream; + gpgme_data_read; + gpgme_data_release; + gpgme_data_release_and_get_mem; + gpgme_data_seek; + gpgme_data_set_encoding; + gpgme_data_write; + + gpgme_get_protocol_name; + gpgme_hash_algo_name; + gpgme_pubkey_algo_name; + + gpgme_new; + gpgme_get_armor; + gpgme_get_include_certs; + gpgme_get_io_cbs; + gpgme_get_keylist_mode; + gpgme_get_passphrase_cb; + gpgme_get_progress_cb; + gpgme_get_protocol; + gpgme_get_textmode; + gpgme_release; + gpgme_set_armor; + gpgme_set_include_certs; + gpgme_set_io_cbs; + gpgme_set_keylist_mode; + gpgme_set_locale; + gpgme_set_passphrase_cb; + gpgme_set_progress_cb; + gpgme_set_protocol; + gpgme_set_textmode; + gpgme_signers_add; + gpgme_signers_clear; + gpgme_signers_enum; + + gpgme_key_ref; + gpgme_key_unref; + gpgme_key_release; + + gpgme_trust_item_ref; + gpgme_trust_item_unref; + + gpgme_cancel; + gpgme_op_card_edit; + gpgme_op_card_edit_start; + gpgme_op_decrypt; + gpgme_op_decrypt_result; + gpgme_op_decrypt_start; + gpgme_op_decrypt_verify; + gpgme_op_decrypt_verify_start; + gpgme_op_delete; + gpgme_op_delete_start; + gpgme_op_edit; + gpgme_op_edit_start; + gpgme_op_encrypt; + gpgme_op_encrypt_result; + gpgme_op_encrypt_sign; + gpgme_op_encrypt_sign_start; + gpgme_op_encrypt_start; + gpgme_op_export; + gpgme_op_export_ext; + gpgme_op_export_ext_start; + gpgme_op_export_start; + gpgme_op_genkey; + gpgme_op_genkey_result; + gpgme_op_genkey_start; + gpgme_get_key; + gpgme_op_import; + gpgme_op_import_result; + gpgme_op_import_start; + gpgme_op_keylist_end; + gpgme_op_keylist_ext_start; + gpgme_op_keylist_next; + gpgme_op_keylist_result; + gpgme_op_keylist_start; + gpgme_op_sign; + gpgme_op_sign_result; + gpgme_op_sign_start; + gpgme_op_trustlist_end; + gpgme_op_trustlist_next; + gpgme_op_trustlist_start; + gpgme_op_verify; + gpgme_op_verify_result; + gpgme_op_verify_start; + gpgme_wait; + + gpgme_data_new_with_read_cb; + gpgme_data_rewind; + gpgme_get_sig_status; + gpgme_get_sig_string_attr; + gpgme_get_sig_ulong_attr; + gpgme_get_sig_key; + gpgme_key_get_string_attr; + gpgme_key_get_ulong_attr; + gpgme_key_sig_get_string_attr; + gpgme_key_sig_get_ulong_attr; + gpgme_op_import_ext; + gpgme_trust_item_get_int_attr; + gpgme_trust_item_get_string_attr; + gpgme_trust_item_release; + + local: + *; + +}; diff --git a/libkdenetwork/libgpgme-copy/gpgme/memrchr.c b/libkdenetwork/libgpgme-copy/gpgme/memrchr.c new file mode 100644 index 000000000..21662b1bd --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/memrchr.c @@ -0,0 +1,210 @@ +/* memrchr -- find the last occurrence of a byte in a memory block + Copyright (C) 1991, 93, 96, 97, 99, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Based on strlen implementation by Torbjorn Granlund (tege@sics.se), + with help from Dan Sahlin (dan@sics.se) and + commentary by Jim Blandy (jimb@ai.mit.edu); + adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu), + and implemented by Roland McGrath (roland@ai.mit.edu). + + The GNU C Library 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. + + The GNU C Library 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 the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef __ptr_t +#if defined __cplusplus || (defined __STDC__ && __STDC__) +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +#if defined _LIBC +# include <string.h> +# include <memcopy.h> +#else +# define reg_char char +#endif + +#if defined HAVE_LIMITS_H || defined _LIBC +# include <limits.h> +#endif + +#define LONG_MAX_32_BITS 2147483647 + +#ifndef LONG_MAX +# define LONG_MAX LONG_MAX_32_BITS +#endif + +#include <sys/types.h> + +#undef __memrchr +#undef memrchr + +#ifndef weak_alias +# define __memrchr memrchr +#endif + +/* Search no more than N bytes of S for C. */ +__ptr_t +__memrchr (s, c_in, n) + const __ptr_t s; + int c_in; + size_t n; +{ + const unsigned char *char_ptr; + const unsigned long int *longword_ptr; + unsigned long int longword, magic_bits, charmask; + unsigned reg_char c; + + c = (unsigned char) c_in; + + /* Handle the last few characters by reading one character at a time. + Do this until CHAR_PTR is aligned on a longword boundary. */ + for (char_ptr = (const unsigned char *) s + n; + n > 0 && ((unsigned long int) char_ptr + & (sizeof (longword) - 1)) != 0; + --n) + if (*--char_ptr == c) + return (__ptr_t) char_ptr; + + /* All these elucidatory comments refer to 4-byte longwords, + but the theory applies equally well to 8-byte longwords. */ + + longword_ptr = (const unsigned long int *) char_ptr; + + /* Bits 31, 24, 16, and 8 of this number are zero. Call these bits + the "holes." Note that there is a hole just to the left of + each byte, with an extra at the end: + + bits: 01111110 11111110 11111110 11111111 + bytes: AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD + + The 1-bits make sure that carries propagate to the next 0-bit. + The 0-bits provide holes for carries to fall into. */ + + if (sizeof (longword) != 4 && sizeof (longword) != 8) + abort (); + +#if LONG_MAX <= LONG_MAX_32_BITS + magic_bits = 0x7efefeff; +#else + magic_bits = ((unsigned long int) 0x7efefefe << 32) | 0xfefefeff; +#endif + + /* Set up a longword, each of whose bytes is C. */ + charmask = c | (c << 8); + charmask |= charmask << 16; +#if LONG_MAX > LONG_MAX_32_BITS + charmask |= charmask << 32; +#endif + + /* Instead of the traditional loop which tests each character, + we will test a longword at a time. The tricky part is testing + if *any of the four* bytes in the longword in question are zero. */ + while (n >= sizeof (longword)) + { + /* We tentatively exit the loop if adding MAGIC_BITS to + LONGWORD fails to change any of the hole bits of LONGWORD. + + 1) Is this safe? Will it catch all the zero bytes? + Suppose there is a byte with all zeros. Any carry bits + propagating from its left will fall into the hole at its + least significant bit and stop. Since there will be no + carry from its most significant bit, the LSB of the + byte to the left will be unchanged, and the zero will be + detected. + + 2) Is this worthwhile? Will it ignore everything except + zero bytes? Suppose every byte of LONGWORD has a bit set + somewhere. There will be a carry into bit 8. If bit 8 + is set, this will carry into bit 16. If bit 8 is clear, + one of bits 9-15 must be set, so there will be a carry + into bit 16. Similarly, there will be a carry into bit + 24. If one of bits 24-30 is set, there will be a carry + into bit 31, so all of the hole bits will be changed. + + The one misfire occurs when bits 24-30 are clear and bit + 31 is set; in this case, the hole at bit 31 is not + changed. If we had access to the processor carry flag, + we could close this loophole by putting the fourth hole + at bit 32! + + So it ignores everything except 128's, when they're aligned + properly. + + 3) But wait! Aren't we looking for C, not zero? + Good point. So what we do is XOR LONGWORD with a longword, + each of whose bytes is C. This turns each byte that is C + into a zero. */ + + longword = *--longword_ptr ^ charmask; + + /* Add MAGIC_BITS to LONGWORD. */ + if ((((longword + magic_bits) + + /* Set those bits that were unchanged by the addition. */ + ^ ~longword) + + /* Look at only the hole bits. If any of the hole bits + are unchanged, most likely one of the bytes was a + zero. */ + & ~magic_bits) != 0) + { + /* Which of the bytes was C? If none of them were, it was + a misfire; continue the search. */ + + const unsigned char *cp = (const unsigned char *) longword_ptr; + +#if LONG_MAX > 2147483647 + if (cp[7] == c) + return (__ptr_t) &cp[7]; + if (cp[6] == c) + return (__ptr_t) &cp[6]; + if (cp[5] == c) + return (__ptr_t) &cp[5]; + if (cp[4] == c) + return (__ptr_t) &cp[4]; +#endif + if (cp[3] == c) + return (__ptr_t) &cp[3]; + if (cp[2] == c) + return (__ptr_t) &cp[2]; + if (cp[1] == c) + return (__ptr_t) &cp[1]; + if (cp[0] == c) + return (__ptr_t) cp; + } + + n -= sizeof (longword); + } + + char_ptr = (const unsigned char *) longword_ptr; + + while (n-- > 0) + { + if (*--char_ptr == c) + return (__ptr_t) char_ptr; + } + + return 0; +} +#ifdef weak_alias +weak_alias (__memrchr, memrchr) +#endif diff --git a/libkdenetwork/libgpgme-copy/gpgme/mkstatus b/libkdenetwork/libgpgme-copy/gpgme/mkstatus new file mode 100755 index 000000000..2c6420178 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/mkstatus @@ -0,0 +1,52 @@ +#!/bin/sh +# mkstatus - Extract error strings from rungpg.h +# and create a lookup table +# Copyright (C) 2000 Werner Koch (dd9jn) +# Copyright (C) 2001 g10 Code GmbH +# +# This file is part of GPGME. +# +# GPGME is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# GPGME is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +# resetting collate is important, so that the bsearch works properly +LC_ALL=C +LC_COLLATE=C +export LC_ALL LC_COLLATE + +cat <<EOF +/* Generated automatically by mkstatus */ +/* Do not edit! */ + +struct status_table_s { + const char *name; + gpgme_status_code_t code; +}; + +static struct status_table_s status_table[] = +{ +EOF + +awk ' +/GPGME_STATUS_ENTER/ { okay = 1 } +!okay { next } +/}/ { exit 0 } +/GPGME_STATUS_[A-Za-z_]*/ { sub (/,/, "", $1); printf " { \"%s\", %s },\n", substr($1,14), $1 } +' | sort + +cat <<EOF + {NULL, 0} +}; + +EOF diff --git a/libkdenetwork/libgpgme-copy/gpgme/op-support.c b/libkdenetwork/libgpgme-copy/gpgme/op-support.c new file mode 100644 index 000000000..b7df3f135 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/op-support.c @@ -0,0 +1,280 @@ +/* op-support.c + 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 <errno.h> +#include <string.h> +#include <locale.h> + +#include "gpgme.h" +#include "context.h" +#include "ops.h" + + +gpgme_error_t +_gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, void **hook, + int size, void (*cleanup) (void *)) +{ + struct ctx_op_data *data = ctx->op_data; + while (data && data->type != type) + data = data->next; + if (!data) + { + if (size < 0) + { + *hook = NULL; + return 0; + } + + data = calloc (1, sizeof (struct ctx_op_data) + size); + if (!data) + return gpg_error_from_errno (errno); + data->next = ctx->op_data; + data->type = type; + data->cleanup = cleanup; + data->hook = (void *) (((char *) data) + sizeof (struct ctx_op_data)); + ctx->op_data = data; + } + *hook = data->hook; + return 0; +} + + +/* type is: 0: asynchronous operation (use global or user event loop). + 1: synchronous operation (always use private event loop). + 2: asynchronous private operation (use private or user + event loop). */ +gpgme_error_t +_gpgme_op_reset (gpgme_ctx_t ctx, int type) +{ + gpgme_error_t err = 0; + struct gpgme_io_cbs io_cbs; + + _gpgme_release_result (ctx); + + if (ctx->engine) + { + /* Attempt to reset an existing engine. */ + + err = _gpgme_engine_reset (ctx->engine); + if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } + } + + if (!ctx->engine) + { + gpgme_engine_info_t info; + info = ctx->engine_info; + while (info && info->protocol != ctx->protocol) + info = info->next; + + if (!info) + return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); + + /* Create an engine object. */ + err = _gpgme_engine_new (info, &ctx->engine); + if (err) + return err; + } + + err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype); +#ifdef LC_MESSAGES + if (!err) + err = _gpgme_engine_set_locale (ctx->engine, + LC_MESSAGES, ctx->lc_messages); +#endif + + if (err) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + return err; + } + + if (type == 1 || (type == 2 && !ctx->io_cbs.add)) + { + /* Use private event loop. */ + io_cbs.add = _gpgme_add_io_cb; + io_cbs.add_priv = ctx; + io_cbs.remove = _gpgme_remove_io_cb; + io_cbs.event = _gpgme_wait_private_event_cb; + io_cbs.event_priv = ctx; + } + else if (! ctx->io_cbs.add) + { + /* Use global event loop. */ + io_cbs.add = _gpgme_add_io_cb; + io_cbs.add_priv = ctx; + io_cbs.remove = _gpgme_remove_io_cb; + io_cbs.event = _gpgme_wait_global_event_cb; + io_cbs.event_priv = ctx; + } + else + { + /* Use user event loop. */ + io_cbs.add = _gpgme_wait_user_add_io_cb; + io_cbs.add_priv = ctx; + io_cbs.remove = _gpgme_wait_user_remove_io_cb; + io_cbs.event = _gpgme_wait_user_event_cb; + io_cbs.event_priv = ctx; + } + _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs); + return err; +} + + +/* Parse the INV_RECP status line in ARGS and return the result in + KEY. */ +gpgme_error_t +_gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key) +{ + gpgme_invalid_key_t inv_key; + char *tail; + long int reason; + + inv_key = malloc (sizeof (*inv_key)); + if (!inv_key) + return gpg_error_from_errno (errno); + inv_key->next = NULL; + errno = 0; + reason = strtol (args, &tail, 0); + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (inv_key); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + switch (reason) + { + default: + case 0: + inv_key->reason = gpg_error (GPG_ERR_GENERAL); + break; + + case 1: + inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY); + break; + + case 2: + inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME); + break; + + case 3: + inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE); + break; + + case 4: + inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED); + break; + + case 5: + inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED); + break; + + case 6: + inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN); + break; + + case 7: + inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD); + break; + + case 8: + inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH); + break; + + case 9: + inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY); + break; + + case 10: + inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED); + break; + } + + while (*tail == ' ') + tail++; + if (*tail) + { + inv_key->fpr = strdup (tail); + if (!inv_key->fpr) + { + int saved_errno = errno; + free (inv_key); + return gpg_error_from_errno (saved_errno); + } + } + else + inv_key->fpr = NULL; + + *key = inv_key; + return 0; +} + + +/* Parse the PLAINTEXT status line in ARGS and return the result in + FILENAMEP. */ +gpgme_error_t +_gpgme_parse_plaintext (char *args, char **filenamep) +{ + char *tail; + + while (*args == ' ') + args++; + if (*args == '\0') + return 0; + + /* First argument is file type. */ + while (*args != ' ' && *args != '\0') + args++; + while (*args == ' ') + args++; + if (*args == '\0') + return 0; + + /* Second argument is the timestamp. */ + while (*args != ' ' && *args != '\0') + args++; + while (*args == ' ') + args++; + if (*args == '\0') + return 0; + + tail = args; + while (*tail != ' ' && *tail != '\0') + tail++; + *tail = '\0'; + if (filenamep && *args != '\0') + { + char *filename = strdup (args); + if (!filename) + return gpg_error_from_errno (errno); + + *filenamep = filename; + } + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/ops.h b/libkdenetwork/libgpgme-copy/gpgme/ops.h new file mode 100644 index 000000000..d6a09e52d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/ops.h @@ -0,0 +1,169 @@ +/* ops.h - Internal operation support. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 OPS_H +#define OPS_H + +#include "gpgme.h" +#include "context.h" + + +/* From gpgme.c. */ +void _gpgme_release_result (gpgme_ctx_t ctx); + + +/* From wait.c. */ +gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx); +gpgme_error_t _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond); + + +/* From data.c. */ +gpgme_error_t _gpgme_data_inbound_handler (void *opaque, int fd); +gpgme_error_t _gpgme_data_outbound_handler (void *opaque, int fd); + + +/* From op-support.c. */ + +/* Find or create the op data object of type TYPE. */ +gpgme_error_t _gpgme_op_data_lookup (gpgme_ctx_t ctx, ctx_op_data_id_t type, + void **hook, int size, + void (*cleanup) (void *)); + +/* Prepare a new operation on CTX. */ +gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int synchronous); + +/* Parse the INV_RECP status line in ARGS and return the result in + KEY. */ +gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key); + +/* Parse the PLAINTEXT status line in ARGS and return the result in + FILENAMEP. */ +gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep); + + + +/* From verify.c. */ +gpgme_error_t _gpgme_op_verify_init_result (gpgme_ctx_t ctx); +gpgme_error_t _gpgme_verify_status_handler (void *priv, + gpgme_status_code_t code, + char *args); + + +/* From decrypt.c. */ +gpgme_error_t _gpgme_op_decrypt_init_result (gpgme_ctx_t ctx); +gpgme_error_t _gpgme_decrypt_status_handler (void *priv, + gpgme_status_code_t code, + char *args); + + +/* From sign.c. */ + +/* Create an initial op data object for signing. Needs to be called + once before calling _gpgme_sign_status_handler. */ +gpgme_error_t _gpgme_op_sign_init_result (gpgme_ctx_t ctx); + +/* Process a status line for signing operations. */ +gpgme_error_t _gpgme_sign_status_handler (void *priv, + gpgme_status_code_t code, + char *args); + + +/* From encrypt.c. */ + +/* Create an initial op data object for encrypt. Needs to be called + once before calling _gpgme_encrypt_status_handler. */ +gpgme_error_t _gpgme_op_encrypt_init_result (gpgme_ctx_t ctx); + +/* Process a status line for encryption operations. */ +gpgme_error_t _gpgme_encrypt_status_handler (void *priv, + gpgme_status_code_t code, + char *args); + + +/* From passphrase.c. */ +gpgme_error_t _gpgme_passphrase_status_handler (void *priv, + gpgme_status_code_t code, + char *args); +gpgme_error_t _gpgme_passphrase_command_handler (void *opaque, + gpgme_status_code_t code, + const char *key, int fd, + int *processed); + + +/* From progress.c. */ +gpgme_error_t _gpgme_progress_status_handler (void *priv, + gpgme_status_code_t code, + char *args); + + +/* From key.c. */ +gpgme_error_t _gpgme_key_new (gpgme_key_t *r_key); +gpgme_error_t _gpgme_key_add_subkey (gpgme_key_t key, + gpgme_subkey_t *r_subkey); +gpgme_error_t _gpgme_key_append_name (gpgme_key_t key, char *src); +gpgme_key_sig_t _gpgme_key_add_sig (gpgme_key_t key, char *src); + + +/* From keylist.c. */ +void _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, + void *type_data); + + +/* From trust-item.c. */ + +/* Create a new trust item. */ +gpgme_error_t _gpgme_trust_item_new (gpgme_trust_item_t *r_item); + + +/* From trustlist.c. */ +void _gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type, + void *type_data); + + +/* From version.c. */ + +/* Return true if MY_VERSION is at least REQ_VERSION, and false + otherwise. */ +int _gpgme_compare_versions (const char *my_version, + const char *req_version); +char *_gpgme_get_program_version (const char *const path); + + +/* From sig-notation.c. */ + +/* Create a new, empty signature notation data object. */ +gpgme_error_t _gpgme_sig_notation_create (gpgme_sig_notation_t *notationp, + const char *name, int name_len, + const char *value, int value_len, + gpgme_sig_notation_flags_t flags); + +/* Free the signature notation object and all associated resources. + The object must already be removed from any linked list as the next + pointer is ignored. */ +void _gpgme_sig_notation_free (gpgme_sig_notation_t notation); + +/* Parse a notation or policy URL subpacket. If the packet type is + not known, return no error but NULL in NOTATION. */ +gpgme_error_t _gpgme_parse_notation (gpgme_sig_notation_t *notationp, + int type, int pkflags, int len, + char *data); + +#endif /* OPS_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/passphrase.c b/libkdenetwork/libgpgme-copy/gpgme/passphrase.c new file mode 100644 index 000000000..71326845d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/passphrase.c @@ -0,0 +1,153 @@ +/* passphrase.c - Passphrase callback. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "gpgme.h" +#include "context.h" +#include "ops.h" + + +typedef struct +{ + int no_passphrase; + char *uid_hint; + char *passphrase_info; + int bad_passphrase; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + + if (opd->passphrase_info) + free (opd->passphrase_info); + if (opd->uid_hint) + free (opd->uid_hint); +} + + +gpgme_error_t +_gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, + char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_USERID_HINT: + if (opd->uid_hint) + free (opd->uid_hint); + if (!(opd->uid_hint = strdup (args))) + return gpg_error_from_errno (errno); + break; + + case GPGME_STATUS_BAD_PASSPHRASE: + opd->bad_passphrase++; + opd->no_passphrase = 0; + break; + + case GPGME_STATUS_GOOD_PASSPHRASE: + opd->bad_passphrase = 0; + opd->no_passphrase = 0; + break; + + case GPGME_STATUS_NEED_PASSPHRASE: + case GPGME_STATUS_NEED_PASSPHRASE_SYM: + case GPGME_STATUS_NEED_PASSPHRASE_PIN: + if (opd->passphrase_info) + free (opd->passphrase_info); + opd->passphrase_info = strdup (args); + if (!opd->passphrase_info) + return gpg_error_from_errno (errno); + break; + + case GPGME_STATUS_MISSING_PASSPHRASE: + opd->no_passphrase = 1; + break; + + case GPGME_STATUS_EOF: + if (opd->no_passphrase || opd->bad_passphrase) + return gpg_error (GPG_ERR_BAD_PASSPHRASE); + break; + + default: + /* Ignore all other codes. */ + break; + } + return 0; +} + + +gpgme_error_t +_gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code, + const char *key, int fd, int *processed) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + assert (ctx->passphrase_cb); + + err = _gpgme_op_data_lookup (ctx, OPDATA_PASSPHRASE, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + + if (code == GPGME_STATUS_GET_HIDDEN + && (!strcmp (key, "passphrase.enter") + || !strcmp (key, "passphrase.pin.ask"))) + { + if (processed) + *processed = 1; + + err = ctx->passphrase_cb (ctx->passphrase_cb_value, + opd->uid_hint, opd->passphrase_info, + opd->bad_passphrase, fd); + + /* Reset bad passphrase flag, in case it is correct now. */ + opd->bad_passphrase = 0; + + return err; + } + + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/posix-io.c b/libkdenetwork/libgpgme-copy/gpgme/posix-io.c new file mode 100644 index 000000000..5cb71f9b8 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/posix-io.c @@ -0,0 +1,497 @@ +/* posix-io.c - Posix I/O functions + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "util.h" +#include "priv-io.h" +#include "sema.h" +#include "ath.h" +#include "debug.h" + + +void +_gpgme_io_subsystem_init (void) +{ + struct sigaction act; + + sigaction (SIGPIPE, NULL, &act); + if (act.sa_handler == SIG_DFL) + { + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (SIGPIPE, &act, NULL); + } +} + + +/* Write the printable version of FD to the buffer BUF of length + BUFLEN. The printable version is the representation on the command + line that the child process expects. */ +int +_gpgme_io_fd2str (char *buf, int buflen, int fd) +{ + return snprintf (buf, buflen, "%d", fd); +} + + +static struct +{ + void (*handler) (int,void*); + void *value; +} notify_table[256]; + +int +_gpgme_io_read (int fd, void *buffer, size_t count) +{ + int nread; + int saved_errno; + + DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count); + do + { + nread = _gpgme_ath_read (fd, buffer, count); + } + while (nread == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: got %d bytes\n", fd, nread); + if (nread > 0) + _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer); + errno = saved_errno; + return nread; +} + + +int +_gpgme_io_write (int fd, const void *buffer, size_t count) +{ + int saved_errno; + int nwritten; + + DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count); + _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer); + do + { + nwritten = _gpgme_ath_write (fd, buffer, count); + } + while (nwritten == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten); + errno = saved_errno; + return nwritten; +} + + +int +_gpgme_io_pipe (int filedes[2], int inherit_idx) +{ + int saved_errno; + int err; + + err = pipe (filedes); + if (err < 0) + return err; + /* FIXME: Should get the old flags first. */ + err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC); + saved_errno = errno; + if (err < 0) + { + close (filedes[0]); + close (filedes[1]); + } + errno = saved_errno; + return err; +} + + +int +_gpgme_io_close (int fd) +{ + if (fd == -1) + return -1; + /* First call the notify handler. */ + DEBUG1 ("closing fd %d", fd); + if (fd >= 0 && fd < (int) DIM (notify_table)) + { + if (notify_table[fd].handler) + { + notify_table[fd].handler (fd, notify_table[fd].value); + notify_table[fd].handler = NULL; + notify_table[fd].value = NULL; + } + } + /* Then do the close. */ + return close (fd); +} + + +int +_gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value) +{ + assert (fd != -1); + + if (fd < 0 || fd >= (int) DIM (notify_table)) + return -1; + DEBUG1 ("set notification for fd %d", fd); + notify_table[fd].handler = handler; + notify_table[fd].value = value; + return 0; +} + + +int +_gpgme_io_set_nonblocking (int fd) +{ + int flags; + + flags = fcntl (fd, F_GETFL, 0); + if (flags == -1) + return -1; + flags |= O_NONBLOCK; + return fcntl (fd, F_SETFL, flags); +} + + +static int +_gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal) +{ + int status; + + *r_status = 0; + *r_signal = 0; + if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid) + { + if (WIFSIGNALED (status)) + { + *r_status = 4; /* Need some value here. */ + *r_signal = WTERMSIG (status); + } + else if (WIFEXITED (status)) + *r_status = WEXITSTATUS (status); + else + *r_status = 4; /* Oops. */ + return 1; + } + return 0; +} + + +/* Returns 0 on success, -1 on error. */ +int +_gpgme_io_spawn (const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list) +{ + pid_t pid; + int i; + int status, signo; + + pid = fork (); + if (pid == -1) + return -1; + + if (!pid) + { + /* Intermediate child to prevent zombie processes. */ + if ((pid = fork ()) == 0) + { + /* Child. */ + int duped_stdin = 0; + int duped_stderr = 0; + + /* First close all fds which will not be duped. */ + for (i=0; fd_child_list[i].fd != -1; i++) + if (fd_child_list[i].dup_to == -1) + close (fd_child_list[i].fd); + + /* And now dup and close the rest. */ + for (i=0; fd_child_list[i].fd != -1; i++) + { + if (fd_child_list[i].dup_to != -1) + { + if (dup2 (fd_child_list[i].fd, + fd_child_list[i].dup_to) == -1) + { + DEBUG1 ("dup2 failed in child: %s\n", strerror (errno)); + _exit (8); + } + if (fd_child_list[i].dup_to == 0) + duped_stdin=1; + if (fd_child_list[i].dup_to == 2) + duped_stderr=1; + close (fd_child_list[i].fd); + } + } + + if (!duped_stdin || !duped_stderr) + { + int fd = open ("/dev/null", O_RDWR); + if (fd == -1) + { + DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno)); + _exit (8); + } + /* Make sure that the process has a connected stdin. */ + if (!duped_stdin) + { + if (dup2 (fd, 0) == -1) + { + DEBUG1("dup2(/dev/null, 0) failed: %s\n", + strerror (errno)); + _exit (8); + } + } + if (!duped_stderr) + if (dup2 (fd, 2) == -1) + { + DEBUG1 ("dup2(dev/null, 2) failed: %s\n", + strerror (errno)); + _exit (8); + } + close (fd); + } + + execv ( path, argv ); + /* Hmm: in that case we could write a special status code to the + status-pipe. */ + DEBUG1 ("exec of `%s' failed\n", path); + _exit (8); + } /* End child. */ + if (pid == -1) + _exit (1); + else + _exit (0); + } + + _gpgme_io_waitpid (pid, 1, &status, &signo); + if (status) + return -1; + + /* .dup_to is not used in the parent list. */ + for (i = 0; fd_parent_list[i].fd != -1; i++) + _gpgme_io_close (fd_parent_list[i].fd); + + return 0; +} + + +/* + * Select on the list of fds. + * Returns: -1 = error + * 0 = timeout or nothing to select + * >0 = number of signaled fds + */ +int +_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ + fd_set readfds; + fd_set writefds; + unsigned int i; + int any, max_fd, n, count; + struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */ + void *dbg_help = NULL; + + FD_ZERO (&readfds); + FD_ZERO (&writefds); + max_fd = 0; + if (nonblock) + timeout.tv_sec = 0; + + DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ "); + any = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if (fds[i].frozen) + DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd); + else if (fds[i].for_read) + { + assert (!FD_ISSET (fds[i].fd, &readfds)); + FD_SET (fds[i].fd, &readfds); + if (fds[i].fd > max_fd) + max_fd = fds[i].fd; + DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd); + any = 1; + } + else if (fds[i].for_write) + { + assert (!FD_ISSET (fds[i].fd, &writefds)); + FD_SET (fds[i].fd, &writefds); + if (fds[i].fd > max_fd) + max_fd = fds[i].fd; + DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd); + any = 1; + } + fds[i].signaled = 0; + } + DEBUG_END (dbg_help, "]"); + if (!any) + return 0; + + do + { + count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL, + &timeout); + } + while (count < 0 && errno == EINTR); + if (count < 0) + { + int saved_errno = errno; + DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno)); + errno = saved_errno; + return -1; /* error */ + } + + DEBUG_BEGIN (dbg_help, 3, "select OK [ "); + if (DEBUG_ENABLED (dbg_help)) + { + for (i = 0; i <= max_fd; i++) + { + if (FD_ISSET (i, &readfds)) + DEBUG_ADD1 (dbg_help, "r%d ", i); + if (FD_ISSET (i, &writefds)) + DEBUG_ADD1 (dbg_help, "w%d ", i); + } + DEBUG_END (dbg_help, "]"); + } + + /* n is used to optimize it a little bit. */ + for (n = count, i = 0; i < nfds && n; i++) + { + if (fds[i].fd == -1) + ; + else if (fds[i].for_read) + { + if (FD_ISSET (fds[i].fd, &readfds)) + { + fds[i].signaled = 1; + n--; + } + } + else if (fds[i].for_write) + { + if (FD_ISSET (fds[i].fd, &writefds)) + { + fds[i].signaled = 1; + n--; + } + } + } + return count; +} + + +int +_gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags) +{ + int nread; + int saved_errno; + struct iovec *iov; + + nread = 0; + iov = msg->msg_iov; + while (iov < msg->msg_iov + msg->msg_iovlen) + { + nread += iov->iov_len; + iov++; + } + + DEBUG2 ("fd %d: about to receive %d bytes\n", + fd, (int) nread); + do + { + nread = _gpgme_ath_recvmsg (fd, msg, flags); + } + while (nread == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: got %d bytes\n", fd, nread); + if (nread > 0) + { + int nr = nread; + + iov = msg->msg_iov; + while (nr > 0) + { + int len = nr > iov->iov_len ? iov->iov_len : nr; + _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, len, + msg->msg_iov->iov_base); + iov++; + nr -= len; + } + } + errno = saved_errno; + return nread; +} + + +int +_gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags) +{ + int saved_errno; + int nwritten; + struct iovec *iov; + + nwritten = 0; + iov = msg->msg_iov; + while (iov < msg->msg_iov + msg->msg_iovlen) + { + nwritten += iov->iov_len; + iov++; + } + + DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) nwritten); + iov = msg->msg_iov; + while (nwritten > 0) + { + int len = nwritten > iov->iov_len ? iov->iov_len : nwritten; + _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, len, + msg->msg_iov->iov_base); + iov++; + nwritten -= len; + } + + do + { + nwritten = _gpgme_ath_sendmsg (fd, msg, flags); + } + while (nwritten == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten); + errno = saved_errno; + return nwritten; +} + + diff --git a/libkdenetwork/libgpgme-copy/gpgme/posix-sema.c b/libkdenetwork/libgpgme-copy/gpgme/posix-sema.c new file mode 100644 index 000000000..fa2b8d37b --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/posix-sema.c @@ -0,0 +1,62 @@ +/* posix-sema.c + Copyright (C) 2001 Werner Koch (dd9jn) + Copyright (C) 2001, 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "util.h" +#include "sema.h" +#include "ath.h" + +void +_gpgme_sema_subsystem_init () +{ +} + +void +_gpgme_sema_cs_enter (struct critsect_s *s) +{ + _gpgme_ath_mutex_lock (&s->private); +} + +void +_gpgme_sema_cs_leave (struct critsect_s *s) +{ + _gpgme_ath_mutex_unlock (&s->private); +} + +void +_gpgme_sema_cs_destroy (struct critsect_s *s) +{ + _gpgme_ath_mutex_destroy (&s->private); + s->private = NULL; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/posix-util.c b/libkdenetwork/libgpgme-copy/gpgme/posix-util.c new file mode 100644 index 000000000..d5b4172d7 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/posix-util.c @@ -0,0 +1,57 @@ +/* posix-util.c - Utility functions for Posix + Copyright (C) 2001 Werner Koch (dd9jn) + Copyright (C) 2001, 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "util.h" + +const char * +_gpgme_get_gpg_path (void) +{ +#ifdef GPG_PATH + return GPG_PATH; +#else + return NULL; +#endif +} + +const char * +_gpgme_get_gpgsm_path (void) +{ +#ifdef GPGSM_PATH + return GPGSM_PATH; +#else + return NULL; +#endif +} + +/* See w32-util.c */ +int +_gpgme_get_conf_int (const char *key, int *value) +{ + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/priv-io.h b/libkdenetwork/libgpgme-copy/gpgme/priv-io.h new file mode 100644 index 000000000..4c2a604aa --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/priv-io.h @@ -0,0 +1,67 @@ +/* priv-io.h - Interface to the private I/O functions. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 IO_H +#define IO_H + + +/* A single file descriptor passed to spawn. For child fds, dup_to + specifies the fd it should become in the child. */ +struct spawn_fd_item_s +{ + int fd; + int dup_to; +}; + +struct io_select_fd_s +{ + int fd; + int for_read; + int for_write; + int signaled; + int frozen; + void *opaque; +}; + +/* These function are either defined in posix-io.c or w32-io.c. */ +void _gpgme_io_subsystem_init (void); +int _gpgme_io_read (int fd, void *buffer, size_t count); +int _gpgme_io_write (int fd, const void *buffer, size_t count); +int _gpgme_io_pipe (int filedes[2], int inherit_idx); +int _gpgme_io_close (int fd); +int _gpgme_io_set_close_notify (int fd, void (*handler) (int, void *), + void *value); +int _gpgme_io_set_nonblocking (int fd); + +/* Spawn the executable PATH with ARGV as arguments, after forking + close all fds in FD_PARENT_LIST in the parent and close or dup all + fds in FD_CHILD_LIST in the child. */ +int _gpgme_io_spawn (const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list); +int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock); + +/* Write the printable version of FD to the buffer BUF of length + BUFLEN. The printable version is the representation on the command + line that the child process expects. */ +int _gpgme_io_fd2str (char *buf, int buflen, int fd); + +#endif /* IO_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/progress.c b/libkdenetwork/libgpgme-copy/gpgme/progress.c new file mode 100644 index 000000000..4fe6b6355 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/progress.c @@ -0,0 +1,81 @@ +/* progress.c - status handler for progress status + 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "util.h" +#include "context.h" + + +gpgme_error_t +_gpgme_progress_status_handler (void *priv, gpgme_status_code_t code, + char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + char *p; + char *args_cpy; + int type = 0; + int current = 0; + int total = 0; + + if (code != GPGME_STATUS_PROGRESS || !*args || !ctx->progress_cb) + return 0; + + args_cpy = strdup (args); + if (!args_cpy) + return gpg_error_from_errno (errno); + + p = strchr (args_cpy, ' '); + if (p) + { + *p++ = 0; + if (*p) + { + type = *(unsigned char *)p; + p = strchr (p+1, ' '); + if (p) + { + *p++ = 0; + if (*p) + { + current = atoi (p); + p = strchr (p+1, ' '); + if (p) + { + *p++ = 0; + total = atoi (p); + } + } + } + } + } + + if (type != 'X') + ctx->progress_cb (ctx->progress_cb_value, args_cpy, type, current, total); + + free (args_cpy); + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/putc_unlocked.c b/libkdenetwork/libgpgme-copy/gpgme/putc_unlocked.c new file mode 100644 index 000000000..a15aade87 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/putc_unlocked.c @@ -0,0 +1,31 @@ +/* putc_unlocked.c - Replacement for putc_unlocked. + Copyright (C) 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 <stdio.h> + +int +putc_unlocked (int c, FILE *stream) +{ + return putc (c, stream); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/rungpg.c b/libkdenetwork/libgpgme-copy/gpgme/rungpg.c new file mode 100644 index 000000000..58ab39d8b --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/rungpg.c @@ -0,0 +1,2111 @@ +/* rungpg.c - Gpg Engine. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 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> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <unistd.h> +#include <locale.h> + +#include "gpgme.h" +#include "util.h" +#include "ops.h" +#include "wait.h" +#include "context.h" /*temp hack until we have GpmeData methods to do I/O */ +#include "priv-io.h" +#include "sema.h" +#include "debug.h" + +#include "status-table.h" +#include "engine-backend.h" + + +/* This type is used to build a list of gpg arguments and data + sources/sinks. */ +struct arg_and_data_s +{ + struct arg_and_data_s *next; + gpgme_data_t data; /* If this is not NULL, use arg below. */ + int inbound; /* True if this is used for reading from gpg. */ + int dup_to; + int print_fd; /* Print the fd number and not the special form of it. */ + char arg[1]; /* Used if data above is not used. */ +}; + + +struct fd_data_map_s +{ + gpgme_data_t data; + int inbound; /* true if this is used for reading from gpg */ + int dup_to; + int fd; /* the fd to use */ + int peer_fd; /* the outher side of the pipe */ + void *tag; +}; + + +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]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + engine_status_handler_t fnc; + void *fnc_value; + void *tag; + } status; + + /* This is a kludge - see the comment at colon_line_handler. */ + struct + { + int fd[2]; + size_t bufsize; + char *buffer; + size_t readpos; + int eof; + engine_colon_line_handler_t fnc; /* this indicate use of this structrue */ + void *fnc_value; + void *tag; + colon_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; + + if (gpg->io_cbs.event) + (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data); +} + + +static void +close_notify_handler (int fd, void *opaque) +{ + engine_gpg_t gpg = opaque; + assert (fd != -1); + + if (gpg->status.fd[0] == fd) + { + if (gpg->status.tag) + (*gpg->io_cbs.remove) (gpg->status.tag); + gpg->status.fd[0] = -1; + } + else if (gpg->status.fd[1] == fd) + gpg->status.fd[1] = -1; + else if (gpg->colon.fd[0] == fd) + { + if (gpg->colon.tag) + (*gpg->io_cbs.remove) (gpg->colon.tag); + gpg->colon.fd[0] = -1; + } + else if (gpg->colon.fd[1] == fd) + gpg->colon.fd[1] = -1; + else if (gpg->fd_data_map) + { + int i; + + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->fd_data_map[i].fd == fd) + { + if (gpg->fd_data_map[i].tag) + (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag); + gpg->fd_data_map[i].fd = -1; + break; + } + if (gpg->fd_data_map[i].peer_fd == fd) + { + gpg->fd_data_map[i].peer_fd = -1; + break; + } + } + } +} + +/* 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_ext (engine_gpg_t gpg, const char *arg, int front) +{ + 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; + 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 (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; + 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->status.fd[0] != -1) + _gpgme_io_close (gpg->status.fd[0]); + if (gpg->status.fd[1] != -1) + _gpgme_io_close (gpg->status.fd[1]); + if (gpg->colon.fd[0] != -1) + _gpgme_io_close (gpg->colon.fd[0]); + if (gpg->colon.fd[1] != -1) + _gpgme_io_close (gpg->colon.fd[1]); + if (gpg->fd_data_map) + { + free_fd_data_map (gpg->fd_data_map); + gpg->fd_data_map = NULL; + } + if (gpg->cmd.fd != -1) + _gpgme_io_close (gpg->cmd.fd); + + return 0; +} + +static void +gpg_release (void *engine) +{ + engine_gpg_t gpg = engine; + + if (!gpg) + return; + + gpg_cancel (engine); + + 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 (gpg, buf); + if (rc) + goto leave; + } + + rc = add_arg (gpg, "--no-tty"); + if (!rc) + rc = add_arg (gpg, "--charset"); + if (!rc) + rc = add_arg (gpg, "utf8"); + if (!rc) + rc = add_arg (gpg, "--enable-progress-filter"); + if (rc) + goto leave; + + rc = _gpgme_getenv ("DISPLAY", &dft_display); + if (dft_display) + { + rc = add_arg (gpg, "--display"); + if (!rc) + rc = add_arg (gpg, dft_display); + + free (dft_display); + } + if (rc) + goto leave; + + if (isatty (1)) + { + if (ttyname_r (1, dft_ttyname, sizeof (dft_ttyname))) + rc = gpg_error_from_errno (errno); + else + { + rc = add_arg (gpg, "--ttyname"); + if (!rc) + rc = add_arg (gpg, dft_ttyname); + if (!rc) + { + rc = _gpgme_getenv ("TERM", &dft_ttytype); + if (!rc) + goto leave; + + 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 (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 (); + } + } +#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) +{ + gpgme_error_t err; + engine_gpg_t gpg = (engine_gpg_t) opaque; + 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); + if (err) + return err; + + /* We always need to send at least a newline character. */ + if (!processed) + _gpgme_io_write (fd, "\n", 1); + + gpg->cmd.code = 0; + /* And sleep again until read_status will wake us up again. */ + /* XXX We must check if there are any more fds active after removing + this one. */ + (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; + gpg->fd_data_map[gpg->cmd.idx].fd = -1; + + return 0; +} + + + +/* The Fnc will be called to get a value for one of the commands with + a key KEY. If the Code pssed to FNC is 0, the function may release + resources associated with the returned value from another call. To + match such a second call to a first call, the returned value from + the first call is passed as keyword. */ +static gpgme_error_t +gpg_set_command_handler (void *engine, engine_command_handler_t fnc, + void *fnc_value, gpgme_data_t linked_data) +{ + engine_gpg_t gpg = engine; + gpgme_error_t rc; + + rc = add_arg (gpg, "--command-fd"); + if (rc) + return rc; + + /* This is a hack. We don't have a real data object. The only + thing that matters is that we use something unique, so we use the + address of the cmd structure in the gpg object. */ + rc = add_data (gpg, (void *) &gpg->cmd, -2, 0); + if (rc) + return rc; + + gpg->cmd.fnc = fnc; + gpg->cmd.cb_data = (void *) &gpg->cmd; + gpg->cmd.fnc_value = fnc_value; + gpg->cmd.linked_data = linked_data; + gpg->cmd.used = 1; + return 0; +} + + +static gpgme_error_t +build_argv (engine_gpg_t gpg) +{ + gpgme_error_t err; + struct arg_and_data_s *a; + struct fd_data_map_s *fd_data_map; + size_t datac=0, argc=0; + char **argv; + int need_special = 0; + int use_agent = 0; + char *p; + + /* We don't want to use the agent with a malformed environment + variable. This is only a very basic test but sufficient to make + our life in the regression tests easier. */ + err = _gpgme_getenv ("GPG_AGENT_INFO", &p); + if (err) + return err; + use_agent = (p && strchr (p, ':')); + if (p) + free (p); + + if (gpg->argv) + { + free_argv (gpg->argv); + gpg->argv = NULL; + } + if (gpg->fd_data_map) + { + free_fd_data_map (gpg->fd_data_map); + gpg->fd_data_map = NULL; + } + + argc++; /* For argv[0]. */ + for (a = gpg->arglist; a; a = a->next) + { + argc++; + if (a->data) + { + /*fprintf (stderr, "build_argv: data\n" );*/ + datac++; + if (a->dup_to == -1 && !a->print_fd) + need_special = 1; + } + else + { + /* fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ + } + } + if (need_special) + argc++; + if (use_agent) + argc++; + if (!gpg->cmd.used) + argc++; /* --batch */ + argc += 1; /* --no-sk-comment */ + + argv = calloc (argc + 1, sizeof *argv); + if (!argv) + return gpg_error_from_errno (errno); + fd_data_map = calloc (datac + 1, sizeof *fd_data_map); + if (!fd_data_map) + { + int saved_errno = errno; + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + + argc = datac = 0; + argv[argc] = strdup ("gpg"); /* argv[0] */ + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + if (need_special) + { + argv[argc] = strdup ("--enable-special-filenames"); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + } + if (use_agent) + { + argv[argc] = strdup ("--use-agent"); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + } + if (!gpg->cmd.used) + { + argv[argc] = strdup ("--batch"); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + } + argv[argc] = strdup ("--no-sk-comment"); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + for (a = gpg->arglist; a; a = a->next) + { + if (a->data) + { + /* Create a pipe to pass it down to gpg. */ + fd_data_map[datac].inbound = a->inbound; + + /* Create a pipe. */ + { + int fds[2]; + + if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0) + == -1) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error (saved_errno); + } + if (_gpgme_io_set_close_notify (fds[0], + close_notify_handler, gpg) + || _gpgme_io_set_close_notify (fds[1], + close_notify_handler, + gpg)) + { + return gpg_error (GPG_ERR_GENERAL); + } + /* If the data_type is FD, we have to do a dup2 here. */ + if (fd_data_map[datac].inbound) + { + fd_data_map[datac].fd = fds[0]; + fd_data_map[datac].peer_fd = fds[1]; + } + else + { + fd_data_map[datac].fd = fds[1]; + fd_data_map[datac].peer_fd = fds[0]; + } + } + + /* Hack to get hands on the fd later. */ + if (gpg->cmd.used) + { + if (gpg->cmd.cb_data == a->data) + { + assert (gpg->cmd.idx == -1); + gpg->cmd.idx = datac; + } + else if (gpg->cmd.linked_data == a->data) + { + assert (gpg->cmd.linked_idx == -1); + gpg->cmd.linked_idx = datac; + } + } + + fd_data_map[datac].data = a->data; + fd_data_map[datac].dup_to = a->dup_to; + if (a->dup_to == -1) + { + 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); + argc++; + } + datac++; + } + else + { + argv[argc] = strdup (a->arg); + if (!argv[argc]) + { + int saved_errno = errno; + free (fd_data_map); + free_argv (argv); + return gpg_error_from_errno (saved_errno); + } + argc++; + } + } + + gpg->argv = argv; + gpg->fd_data_map = fd_data_map; + return 0; +} + + +static gpgme_error_t +add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data, + void **tag) +{ + gpgme_error_t err; + + err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag); + if (err) + return err; + if (!dir) + /* FIXME Kludge around poll() problem. */ + err = _gpgme_io_set_nonblocking (fd); + return err; +} + + +static int +status_cmp (const void *ap, const void *bp) +{ + const struct status_table_s *a = ap; + const struct status_table_s *b = bp; + + return strcmp (a->name, b->name); +} + + +/* Handle the status output of GnuPG. This function does read entire + lines and passes them as C strings to the callback function (we can + use C Strings because the status output is always UTF-8 encoded). + Of course we have to buffer the lines to cope with long lines + e.g. with a large user ID. Note: We can optimize this to only cope + with status line code we know about and skip all other stuff + without buffering (i.e. without extending the buffer). */ +static gpgme_error_t +read_status (engine_gpg_t gpg) +{ + char *p; + int nread; + size_t bufsize = gpg->status.bufsize; + char *buffer = gpg->status.buffer; + size_t readpos = gpg->status.readpos; + + assert (buffer); + if (bufsize - readpos < 256) + { + /* Need more room for the read. */ + bufsize += 1024; + buffer = realloc (buffer, bufsize); + if (!buffer) + return gpg_error_from_errno (errno); + } + + nread = _gpgme_io_read (gpg->status.fd[0], + buffer + readpos, bufsize-readpos); + if (nread == -1) + return gpg_error_from_errno (errno); + + if (!nread) + { + gpg->status.eof = 1; + if (gpg->status.fnc) + { + gpgme_error_t err; + err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, ""); + if (err) + return err; + } + return 0; + } + + while (nread > 0) + { + for (p = buffer + readpos; nread; nread--, p++) + { + if (*p == '\n') + { + /* (we require that the last line is terminated by a LF) */ + if (p > buffer && p[-1] == '\r') + p[-1] = 0; + *p = 0; + if (!strncmp (buffer, "[GNUPG:] ", 9) + && buffer[9] >= 'A' && buffer[9] <= 'Z') + { + struct status_table_s t, *r; + char *rest; + + rest = strchr (buffer + 9, ' '); + if (!rest) + rest = p; /* Set to an empty string. */ + else + *rest++ = 0; + + t.name = buffer+9; + /* (the status table has one extra element) */ + r = bsearch (&t, status_table, DIM(status_table) - 1, + sizeof t, status_cmp); + if (r) + { + if (gpg->cmd.used + && (r->code == GPGME_STATUS_GET_BOOL + || r->code == GPGME_STATUS_GET_LINE + || r->code == GPGME_STATUS_GET_HIDDEN)) + { + gpg->cmd.code = r->code; + if (gpg->cmd.keyword) + free (gpg->cmd.keyword); + gpg->cmd.keyword = strdup (rest); + if (!gpg->cmd.keyword) + return gpg_error_from_errno (errno); + /* This should be the last thing we have + received and the next thing will be that + the command handler does its action. */ + if (nread > 1) + DEBUG0 ("ERROR, unexpected data in read_status"); + + add_io_cb (gpg, gpg->cmd.fd, 0, + command_handler, gpg, + &gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd; + gpg->cmd.fd = -1; + } + else if (gpg->status.fnc) + { + gpgme_error_t err; + err = gpg->status.fnc (gpg->status.fnc_value, + r->code, rest); + if (err) + return err; + } + + if (r->code == GPGME_STATUS_END_STREAM) + { + if (gpg->cmd.used) + { + /* Before we can actually add the + command fd, we might have to flush + the linked output data pipe. */ + if (gpg->cmd.linked_idx != -1 + && gpg->fd_data_map[gpg->cmd.linked_idx].fd + != -1) + { + struct io_select_fd_s fds; + fds.fd = + gpg->fd_data_map[gpg->cmd.linked_idx].fd; + fds.for_read = 1; + fds.for_write = 0; + fds.frozen = 0; + fds.opaque = NULL; + do + { + fds.signaled = 0; + _gpgme_io_select (&fds, 1, 1); + if (fds.signaled) + _gpgme_data_inbound_handler + (gpg->cmd.linked_data, fds.fd); + } + while (fds.signaled); + } + + /* XXX We must check if there are any + more fds active after removing this + one. */ + (*gpg->io_cbs.remove) + (gpg->fd_data_map[gpg->cmd.idx].tag); + gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; + gpg->fd_data_map[gpg->cmd.idx].fd = -1; + } + } + } + } + /* To reuse the buffer for the next line we have to + shift the remaining data to the buffer start and + restart the loop Hmmm: We can optimize this function + by looking forward in the buffer to see whether a + second complete line is available and in this case + avoid the memmove for this line. */ + nread--; p++; + if (nread) + memmove (buffer, p, nread); + readpos = 0; + break; /* the for loop */ + } + else + readpos++; + } + } + + /* Update the gpg object. */ + gpg->status.bufsize = bufsize; + gpg->status.buffer = buffer; + gpg->status.readpos = readpos; + return 0; +} + + +static gpgme_error_t +status_handler (void *opaque, int fd) +{ + engine_gpg_t gpg = opaque; + int err; + + assert (fd == gpg->status.fd[0]); + err = read_status (gpg); + if (err) + return err; + if (gpg->status.eof) + _gpgme_io_close (fd); + return 0; +} + + +static gpgme_error_t +read_colon_line (engine_gpg_t gpg) +{ + char *p; + int nread; + size_t bufsize = gpg->colon.bufsize; + char *buffer = gpg->colon.buffer; + size_t readpos = gpg->colon.readpos; + + assert (buffer); + if (bufsize - readpos < 256) + { + /* Need more room for the read. */ + bufsize += 1024; + buffer = realloc (buffer, bufsize); + if (!buffer) + return gpg_error_from_errno (errno); + } + + nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos); + if (nread == -1) + return gpg_error_from_errno (errno); + + if (!nread) + { + gpg->colon.eof = 1; + assert (gpg->colon.fnc); + gpg->colon.fnc (gpg->colon.fnc_value, NULL); + return 0; + } + + while (nread > 0) + { + for (p = buffer + readpos; nread; nread--, p++) + { + if ( *p == '\n' ) + { + /* (we require that the last line is terminated by a LF) + and we skip empty lines. Note: we use UTF8 encoding + and escaping of special characters. We require at + least one colon to cope with some other printed + information. */ + *p = 0; + if (*buffer && strchr (buffer, ':')) + { + 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) +{ + engine_gpg_t gpg = opaque; + gpgme_error_t rc = 0; + + assert (fd == gpg->colon.fd[0]); + rc = read_colon_line (gpg); + if (rc) + return rc; + if (gpg->colon.eof) + _gpgme_io_close (fd); + return 0; +} + + +static gpgme_error_t +start (engine_gpg_t gpg) +{ + gpgme_error_t rc; + int saved_errno; + int i, n; + int status; + struct spawn_fd_item_s *fd_child_list, *fd_parent_list; + + if (!gpg) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!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; + + n = 3; /* status_fd, colon_fd and end of list */ + for (i = 0; gpg->fd_data_map[i].data; i++) + n++; + fd_child_list = calloc (n + n, sizeof *fd_child_list); + if (!fd_child_list) + return gpg_error_from_errno (errno); + fd_parent_list = fd_child_list + n; + + /* build the fd list for the child */ + n = 0; + if (gpg->colon.fnc) + { + fd_child_list[n].fd = gpg->colon.fd[1]; + fd_child_list[n].dup_to = 1; /* dup to stdout */ + n++; + } + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->fd_data_map[i].dup_to != -1) + { + fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; + n++; + } + } + fd_child_list[n].fd = -1; + fd_child_list[n].dup_to = -1; + + /* Build the fd list for the parent. */ + n = 0; + if (gpg->status.fd[1] != -1) + { + fd_parent_list[n].fd = gpg->status.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + } + if (gpg->colon.fd[1] != -1) + { + fd_parent_list[n].fd = gpg->colon.fd[1]; + fd_parent_list[n].dup_to = -1; + n++; + } + for (i = 0; gpg->fd_data_map[i].data; i++) + { + fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; + fd_parent_list[n].dup_to = -1; + n++; + } + fd_parent_list[n].fd = -1; + fd_parent_list[n].dup_to = -1; + + status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name : + _gpgme_get_gpg_path (), + gpg->argv, fd_child_list, fd_parent_list); + saved_errno = errno; + free (fd_child_list); + if (status == -1) + return gpg_error_from_errno (saved_errno); + + /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ + + rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg, + &gpg->status.tag); + if (rc) + /* FIXME: kill the child */ + return rc; + + if (gpg->colon.fnc) + { + assert (gpg->colon.fd[0] != -1); + rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg, + &gpg->colon.tag); + if (rc) + /* FIXME: kill the child */ + return rc; + } + + for (i = 0; gpg->fd_data_map[i].data; i++) + { + if (gpg->cmd.used && i == gpg->cmd.idx) + { + /* Park the cmd fd. */ + gpg->cmd.fd = gpg->fd_data_map[i].fd; + gpg->fd_data_map[i].fd = -1; + } + else + { + rc = add_io_cb (gpg, gpg->fd_data_map[i].fd, + gpg->fd_data_map[i].inbound, + gpg->fd_data_map[i].inbound + ? _gpgme_data_inbound_handler + : _gpgme_data_outbound_handler, + gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag); + + if (rc) + /* FIXME: kill the child */ + return rc; + } + } + + (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL); + + /* fixme: check what data we can release here */ + return 0; +} + + +static gpgme_error_t +gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = add_arg (gpg, "--decrypt"); + + /* Tell the gpg object about the data. */ + if (!err) + err = add_arg (gpg, "--output"); + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_data (gpg, plain, 1, 1); + if (!err) + err = add_data (gpg, ciph, 0, 0); + + if (!err) + start (gpg); + return err; +} + +static gpgme_error_t +gpg_delete (void *engine, gpgme_key_t key, int allow_secret) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key" + : "--delete-key"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + { + if (!key->subkeys || !key->subkeys->fpr) + return gpg_error (GPG_ERR_INV_VALUE); + else + err = add_arg (gpg, key->subkeys->fpr); + } + + if (!err) + start (gpg); + return err; +} + + +static gpgme_error_t +append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */) +{ + gpgme_error_t err = 0; + int i; + gpgme_key_t key; + + for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++) + { + const char *s = key->subkeys ? key->subkeys->keyid : NULL; + if (s) + { + if (!err) + err = add_arg (gpg, "-u"); + if (!err) + err = add_arg (gpg, s); + } + gpgme_key_unref (key); + if (err) break; + } + return err; +} + + +static gpgme_error_t +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 && !symmetric && (flags & GPGME_ENCRYPT_ALWAYS_TRUST)) + err = add_arg (gpg, "--always-trust"); + + if (!err) + err = append_args_from_recipients (gpg, recp); + } + + /* Tell the gpg object about the data. */ + if (!err) + err = add_arg (gpg, "--output"); + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_data (gpg, ciph, 1, 1); + if (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, 0, 0); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_encrypt_sign (void *engine, gpgme_key_t recp[], + gpgme_encrypt_flags_t flags, gpgme_data_t plain, + gpgme_data_t ciph, int use_armor, + gpgme_ctx_t ctx /* FIXME */) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = add_arg (gpg, "--encrypt"); + if (!err) + err = add_arg (gpg, "--sign"); + if (!err && use_armor) + err = add_arg (gpg, "--armor"); + + /* If we know that all recipients are valid (full or ultimate trust) + we can suppress further checks. */ + if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST)) + err = add_arg (gpg, "--always-trust"); + + if (!err) + err = append_args_from_recipients (gpg, recp); + + if (!err) + err = append_args_from_signers (gpg, ctx); + 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, 0, 0); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_export (void *engine, const char *pattern, unsigned int reserved, + gpgme_data_t keydata, int use_armor) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + err = add_arg (gpg, "--export"); + if (!err && use_armor) + err = add_arg (gpg, "--armor"); + if (!err) + err = add_data (gpg, keydata, 1, 1); + if (!err) + err = add_arg (gpg, "--"); + + if (!err && pattern && *pattern) + err = add_arg (gpg, pattern); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved, + gpgme_data_t keydata, int use_armor) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + err = add_arg (gpg, "--export"); + if (!err && use_armor) + err = add_arg (gpg, "--armor"); + if (!err) + err = add_data (gpg, keydata, 1, 1); + if (!err) + err = add_arg (gpg, "--"); + + if (pattern) + { + while (!err && *pattern && **pattern) + err = add_arg (gpg, *(pattern++)); + } + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor, + gpgme_data_t pubkey, gpgme_data_t seckey) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (!gpg) + return gpg_error (GPG_ERR_INV_VALUE); + + /* We need a special mechanism to get the fd of a pipe here, so that + we can use this for the %pubring and %secring parameters. We + don't have this yet, so we implement only the adding to the + standard keyrings. */ + if (pubkey || seckey) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + err = add_arg (gpg, "--gen-key"); + if (!err && use_armor) + err = add_arg (gpg, "--armor"); + if (!err) + err = add_data (gpg, help_data, 0, 0); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_import (void *engine, gpgme_data_t keydata) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = add_arg (gpg, "--import"); + if (!err) + err = add_data (gpg, keydata, 0, 0); + + if (!err) + err = start (gpg); + + return err; +} + + +/* 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>:::<uid>: + */ + + if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:", + field[4], field[2], field[3], field[1]) < 0) + return gpg_error_from_errno (errno); + return 0; + + case RT_NONE: + /* Unknown record. */ + break; + } + return 0; + +} + + +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; + + if (mode & GPGME_KEYLIST_MODE_EXTERN) + { + if ((mode & GPGME_KEYLIST_MODE_LOCAL) + || secret_only) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + } + + 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) + { + 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")); + } + } + + /* Tell the gpg object about the data. */ + if (!err) + err = add_arg (gpg, "--"); + if (!err && pattern && *pattern) + err = add_arg (gpg, pattern); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_keylist_ext (void *engine, const char *pattern[], int secret_only, + int reserved, gpgme_keylist_mode_t mode) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (reserved) + return gpg_error (GPG_ERR_INV_VALUE); + + err = add_arg (gpg, "--with-colons"); + if (!err) + err = add_arg (gpg, "--fixed-list-mode"); + if (!err) + err = add_arg (gpg, "--with-fingerprint"); + if (!err) + err = add_arg (gpg, "--with-fingerprint"); + if (!err && (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) + err = add_arg (gpg, secret_only ? "--list-secret-keys" + : ((mode & GPGME_KEYLIST_MODE_SIGS) + ? "--check-sigs" : "--list-keys")); + if (!err) + err = add_arg (gpg, "--"); + + if (pattern) + { + while (!err && *pattern && **pattern) + err = add_arg (gpg, *(pattern++)); + } + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, + gpgme_sig_mode_t mode, int use_armor, int use_textmode, + int include_certs, gpgme_ctx_t ctx /* FIXME */) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + if (mode == GPGME_SIG_MODE_CLEAR) + err = add_arg (gpg, "--clearsign"); + else + { + err = add_arg (gpg, "--sign"); + if (!err && mode == GPGME_SIG_MODE_DETACH) + err = add_arg (gpg, "--detach"); + if (!err && use_armor) + err = add_arg (gpg, "--armor"); + if (!err && use_textmode) + err = add_arg (gpg, "--textmode"); + } + + if (!err) + err = append_args_from_signers (gpg, ctx); + 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_data (gpg, in, 0, 0); + if (!err) + err = add_data (gpg, out, 1, 1); + + if (!err) + start (gpg); + + return err; +} + +static gpgme_error_t +gpg_trustlist (void *engine, const char *pattern) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err; + + err = add_arg (gpg, "--with-colons"); + if (!err) + err = add_arg (gpg, "--list-trust-path"); + + /* Tell the gpg object about the data. */ + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_arg (gpg, pattern); + + if (!err) + err = start (gpg); + + return err; +} + + +static gpgme_error_t +gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, + gpgme_data_t plaintext) +{ + engine_gpg_t gpg = engine; + gpgme_error_t err = 0; + + if (plaintext) + { + /* Normal or cleartext signature. */ + + err = add_arg (gpg, "--output"); + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, sig, 0, 0); + if (!err) + err = add_data (gpg, plaintext, 1, 1); + } + else + { + err = add_arg (gpg, "--verify"); + if (!err) + err = add_arg (gpg, "--"); + if (!err) + err = add_data (gpg, sig, -1, 0); + if (signed_text) + { + if (!err) + err = add_arg (gpg, "-"); + if (!err) + err = add_data (gpg, signed_text, 0, 0); + } + } + + if (!err) + err = start (gpg); + + return err; +} + + +static void +gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs) +{ + engine_gpg_t gpg = engine; + + gpg->io_cbs = *io_cbs; +} + + +struct engine_ops _gpgme_engine_ops_gpg = + { + /* Static functions. */ + _gpgme_get_gpg_path, + gpg_get_version, + gpg_get_req_version, + gpg_new, + + /* Member functions. */ + gpg_release, + NULL, /* reset */ + gpg_set_status_handler, + gpg_set_command_handler, + gpg_set_colon_line_handler, + gpg_set_locale, + gpg_decrypt, + gpg_delete, + gpg_edit, + gpg_encrypt, + gpg_encrypt_sign, + gpg_export, + gpg_export_ext, + gpg_genkey, + gpg_import, + gpg_keylist, + gpg_keylist_ext, + gpg_sign, + gpg_trustlist, + gpg_verify, + gpg_set_io_cbs, + gpg_io_event, + gpg_cancel + }; diff --git a/libkdenetwork/libgpgme-copy/gpgme/sema.h b/libkdenetwork/libgpgme-copy/gpgme/sema.h new file mode 100644 index 000000000..0ee20742e --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/sema.h @@ -0,0 +1,67 @@ +/* sema.h - Definitions for semaphores. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 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 SEMA_H +#define SEMA_H + +struct critsect_s +{ + const char *name; + void *private; +}; + +#define DEFINE_GLOBAL_LOCK(name) \ + struct critsect_s name = { #name, NULL } +#define DEFINE_STATIC_LOCK(name) \ + static struct critsect_s name = { #name, NULL } + +#define DECLARE_LOCK(name) \ + struct critsect_s name +#define INIT_LOCK(a) \ + do \ + { \ + (a).name = #a; \ + (a).private = NULL; \ + } \ + while (0) +#define DESTROY_LOCK(name) _gpgme_sema_cs_destroy (&(name)) + + +#define LOCK(name) \ + do \ + { \ + _gpgme_sema_cs_enter (&(name)); \ + } \ + while (0) + +#define UNLOCK(name) \ + do \ + { \ + _gpgme_sema_cs_leave (&(name)); \ + } \ + while (0) + +void _gpgme_sema_subsystem_init (void); +void _gpgme_sema_cs_enter (struct critsect_s *s); +void _gpgme_sema_cs_leave (struct critsect_s *s); +void _gpgme_sema_cs_destroy (struct critsect_s *s); + +#endif /* SEMA_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/sig-notation.c b/libkdenetwork/libgpgme-copy/gpgme/sig-notation.c new file mode 100644 index 000000000..5800c3784 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/sig-notation.c @@ -0,0 +1,260 @@ +/* sig-notation.c - Signature notation data support. + Copyright (C) 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "gpgme.h" +#include "util.h" +#include "context.h" +#include "ops.h" + + +/* Free the signature notation object and all associated resources. + The object must already be removed from any linked list as the next + pointer is ignored. */ +void +_gpgme_sig_notation_free (gpgme_sig_notation_t notation) +{ + if (notation->name) + free (notation->name); + + if (notation->value) + free (notation->value); + + free (notation); +} + + +/* Set the flags of NOTATION to FLAGS. */ +static void +sig_notation_set_flags (gpgme_sig_notation_t notation, + gpgme_sig_notation_flags_t flags) +{ + /* We copy the flags into individual bits to make them easier + accessible individually for the user. */ + notation->human_readable = flags & GPGME_SIG_NOTATION_HUMAN_READABLE ? 1 : 0; + notation->critical = flags & GPGME_SIG_NOTATION_CRITICAL ? 1 : 0; + + notation->flags = flags; +} + + +/* Create a new, empty signature notation data object. */ +gpgme_error_t +_gpgme_sig_notation_create (gpgme_sig_notation_t *notationp, + const char *name, int name_len, + const char *value, int value_len, + gpgme_sig_notation_flags_t flags) +{ + gpgme_error_t err = 0; + gpgme_sig_notation_t notation; + + /* Currently, we require all notations to be human-readable. */ + if (name && !(flags & GPGME_SIG_NOTATION_HUMAN_READABLE)) + return gpg_error (GPG_ERR_INV_VALUE); + + notation = calloc (1, sizeof (*notation)); + if (!notation) + return gpg_error_from_errno (errno); + + /* This is critical. We want to reliably identify policy URLs by + using a NULL pointer for NAME. So all notations must have a NAME + string, even if it is empty. */ + if (name) + { + /* We add a trailing '\0' for stringification in the good + case. */ + notation->name = malloc (name_len + 1); + if (!notation->name) + { + err = gpg_error_from_errno (errno); + goto err; + } + + memcpy (notation->name, name, name_len); + notation->name[name_len] = '\0'; + notation->name_len = name_len; + } + + if (value) + { + /* We add a trailing '\0' for stringification in the good + case. */ + notation->value = malloc (value_len + 1); + if (!notation->value) + { + err = gpg_error_from_errno (errno); + goto err; + } + + memcpy (notation->value, value, value_len); + notation->value[value_len] = '\0'; + notation->value_len = value_len; + } + + sig_notation_set_flags (notation, flags); + + *notationp = notation; + return 0; + + err: + _gpgme_sig_notation_free (notation); + return err; +} + + +/* GnuPG subpacket flags. */ + +/* This subpacket data is part of the hashed data. */ +#define GNUPG_SPK_HASHED 0x01 + +/* This subpacket is marked critical. */ +#define GNUPG_SPK_CRITICAL 0x02 + +/* Parse a notation or policy URL subpacket. If the packet type is + not known, return no error but NULL in NOTATION. */ +gpgme_error_t +_gpgme_parse_notation (gpgme_sig_notation_t *notationp, + int type, int pkflags, int len, char *data) +{ + gpgme_error_t err; + char *name = NULL; + int name_len = 0; + char *value = NULL; + int value_len = 0; + gpgme_sig_notation_flags_t flags = 0; + char *decoded_data; + unsigned char *bdata; + + /* Type 20: Notation data. */ + /* Type 26: Policy URL. */ + if (type != 20 && type != 26) + { + *notationp = NULL; + return 0; + } + + /* A few simple sanity checks. */ + if (len > strlen (data)) + return gpg_error (GPG_ERR_INV_ENGINE); + + /* See below for the format of a notation subpacket. It has at + least four octets of flags and two times two octets of length + information. */ + if (type == 20 && len < 4 + 2 + 2) + return gpg_error (GPG_ERR_INV_ENGINE); + + err = _gpgme_decode_percent_string (data, &decoded_data, 0, 1); + if (err) + return err; + bdata = (unsigned char *) decoded_data; + + /* Flags common to notation data and policy URL. */ + if (pkflags & GNUPG_SPK_CRITICAL) + flags |= GPGME_SIG_NOTATION_CRITICAL; + + /* This information is relevant in parsing multi-octet numbers below: + + 3.1. Scalar numbers + + Scalar numbers are unsigned, and are always stored in big-endian + format. Using n[k] to refer to the kth octet being interpreted, + the value of a two-octet scalar is ((n[0] << 8) + n[1]). The + value of a four-octet scalar is ((n[0] << 24) + (n[1] << 16) + + (n[2] << 8) + n[3]). + + From RFC2440: OpenPGP Message Format. Copyright (C) The Internet + Society (1998). All Rights Reserved. */ +#define RFC2440_GET_WORD(chr) ((((int)((unsigned char *)(chr))[0]) << 8) \ + + ((int)((unsigned char *)(chr))[1])) + + if (type == 20) + { + /* 5.2.3.15. Notation Data + + (4 octets of flags, 2 octets of name length (M), + 2 octets of value length (N), M octets of name data, + N octets of value data) + + [...] The "flags" field holds four octets of flags. + All undefined flags MUST be zero. Defined flags are: + + First octet: 0x80 = human-readable. [...] + Other octets: none. + + From RFC2440: OpenPGP Message Format. Copyright (C) The + Internet Society (1998). All Rights Reserved. */ + + int chr; + + /* First octet of flags. */ +#define RFC2440_SPK20_FLAG1_HUMAN_READABLE 0x80 + + chr = *bdata; + bdata++; + + if (chr & RFC2440_SPK20_FLAG1_HUMAN_READABLE) + flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; + + /* The second, third and four octet of flags are unused. */ + bdata++; + bdata++; + bdata++; + + name_len = RFC2440_GET_WORD (bdata); + bdata += 2; + + value_len = RFC2440_GET_WORD (bdata); + bdata += 2; + + /* Small sanity check. */ + if (4 + 2 + 2 + name_len + value_len > len) + { + free (decoded_data); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + name = (char *) bdata; + bdata += name_len; + + value = (char *) bdata; + } + else + { + /* Type is 26. */ + + /* NAME is NULL, name_len is 0. */ + + value = (char *) bdata; + value_len = strlen (value); + } + + err = _gpgme_sig_notation_create (notationp, name, name_len, + value, value_len, flags); + + free (decoded_data); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/sign.c b/libkdenetwork/libgpgme-copy/gpgme/sign.c new file mode 100644 index 000000000..310f91798 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/sign.c @@ -0,0 +1,328 @@ +/* sign.c - Signing 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 "context.h" +#include "ops.h" +#include "util.h" + + +typedef struct +{ + struct _gpgme_op_sign_result result; + + /* A pointer to the next pointer of the last invalid signer in + the list. This makes appending new invalid signers painless + while preserving the order. */ + gpgme_invalid_key_t *last_signer_p; + + /* Likewise for signature information. */ + gpgme_new_signature_t *last_sig_p; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_invalid_key_t invalid_signer = opd->result.invalid_signers; + gpgme_new_signature_t sig = opd->result.signatures; + + while (invalid_signer) + { + gpgme_invalid_key_t next = invalid_signer->next; + if (invalid_signer->fpr) + free (invalid_signer->fpr); + free (invalid_signer); + invalid_signer = next; + } + + while (sig) + { + gpgme_new_signature_t next = sig->next; + free (sig->fpr); + free (sig); + sig = next; + } +} + + +gpgme_sign_result_t +gpgme_op_sign_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +static gpgme_error_t +parse_sig_created (char *args, gpgme_new_signature_t *sigp) +{ + gpgme_new_signature_t sig; + char *tail; + + sig = malloc (sizeof (*sig)); + if (!sig) + return gpg_error_from_errno (errno); + + sig->next = NULL; + switch (*args) + { + case 'S': + sig->type = GPGME_SIG_MODE_NORMAL; + break; + + case 'D': + sig->type = GPGME_SIG_MODE_DETACH; + break; + + case 'C': + sig->type = GPGME_SIG_MODE_CLEAR; + break; + + default: + /* The backend engine is not behaving. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + args++; + if (*args != ' ') + { + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + errno = 0; + sig->pubkey_algo = strtol (args, &tail, 0); + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + args = tail; + + sig->hash_algo = strtol (args, &tail, 0); + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + args = tail; + + sig->sig_class = strtol (args, &tail, 0); + sig->class = sig->sig_class; + sig->_obsolete_class = sig->sig_class; + if (errno || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + args = tail; + + sig->timestamp = _gpgme_parse_timestamp (args, &tail); + if (sig->timestamp == -1 || args == tail || *tail != ' ') + { + /* The crypto backend does not behave. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + args = tail; + while (*args == ' ') + args++; + + if (!*args) + { + /* The crypto backend does not behave. */ + free (sig); + return gpg_error (GPG_ERR_INV_ENGINE); + } + + tail = strchr (args, ' '); + if (tail) + *tail = '\0'; + + sig->fpr = strdup (args); + if (!sig->fpr) + { + int saved_errno = errno; + free (sig); + return gpg_error_from_errno (saved_errno); + } + *sigp = sig; + return 0; +} + + +gpgme_error_t +_gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_passphrase_status_handler (priv, code, args); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + switch (code) + { + case GPGME_STATUS_SIG_CREATED: + err = parse_sig_created (args, opd->last_sig_p); + if (err) + return err; + + opd->last_sig_p = &(*opd->last_sig_p)->next; + break; + + case GPGME_STATUS_INV_RECP: + err = _gpgme_parse_inv_recp (args, opd->last_signer_p); + if (err) + return err; + + opd->last_signer_p = &(*opd->last_signer_p)->next; + break; + + case GPGME_STATUS_EOF: + if (opd->result.invalid_signers) + return gpg_error (GPG_ERR_UNUSABLE_SECKEY); + break; + + default: + break; + } + return err; +} + + +static gpgme_error_t +sign_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_sign_status_handler (priv, code, args); + return err; +} + + +gpgme_error_t +_gpgme_op_sign_init_result (gpgme_ctx_t ctx) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + opd->last_signer_p = &opd->result.invalid_signers; + opd->last_sig_p = &opd->result.signatures; + return 0; +} + + +static gpgme_error_t +sign_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t plain, + gpgme_data_t sig, gpgme_sig_mode_t mode) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_sign_init_result (ctx); + if (err) + return err; + + if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH + && mode != GPGME_SIG_MODE_CLEAR) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!plain) + return gpg_error (GPG_ERR_NO_DATA); + if (!sig) + return gpg_error (GPG_ERR_INV_VALUE); + + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + + _gpgme_engine_set_status_handler (ctx->engine, sign_status_handler, + ctx); + + return _gpgme_engine_op_sign (ctx->engine, plain, sig, mode, ctx->use_armor, + ctx->use_textmode, ctx->include_certs, + ctx /* FIXME */); +} + + +/* Sign the plaintext PLAIN and store the signature in SIG. */ +gpgme_error_t +gpgme_op_sign_start (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig, + gpgme_sig_mode_t mode) +{ + return sign_start (ctx, 0, plain, sig, mode); +} + + +/* Sign the plaintext PLAIN and store the signature in SIG. */ +gpgme_error_t +gpgme_op_sign (gpgme_ctx_t ctx, gpgme_data_t plain, gpgme_data_t sig, + gpgme_sig_mode_t mode) +{ + gpgme_error_t err = sign_start (ctx, 1, plain, sig, mode); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/signers.c b/libkdenetwork/libgpgme-copy/gpgme/signers.c new file mode 100644 index 000000000..f1ce58f17 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/signers.c @@ -0,0 +1,95 @@ +/* signers.c - Maintain signer sets. + Copyright (C) 2001 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 <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> + +#include "util.h" +#include "context.h" + + +/* Delete all signers from CTX. */ +void +gpgme_signers_clear (gpgme_ctx_t ctx) +{ + unsigned int i; + + if (!ctx || !ctx->signers) + return; + + for (i = 0; i < ctx->signers_len; i++) + { + assert (ctx->signers[i]); + gpgme_key_unref (ctx->signers[i]); + ctx->signers[i] = NULL; + } + ctx->signers_len = 0; +} + +/* Add KEY to list of signers in CTX. */ +gpgme_error_t +gpgme_signers_add (gpgme_ctx_t ctx, const gpgme_key_t key) +{ + if (!ctx || !key) + return gpg_error (GPG_ERR_INV_VALUE); + + if (ctx->signers_len == ctx->signers_size) + { + gpgme_key_t *newarr; + int n = ctx->signers_size + 5; + int j; + + newarr = realloc (ctx->signers, n * sizeof (*newarr)); + if (!newarr) + return gpg_error_from_errno (errno); + for (j = ctx->signers_size; j < n; j++) + newarr[j] = NULL; + ctx->signers = newarr; + ctx->signers_size = n; + } + + gpgme_key_ref (key); + ctx->signers[ctx->signers_len++] = key; + return 0; +} + + +/* Return the SEQth signer's key in CTX with one reference. */ +gpgme_key_t +gpgme_signers_enum (const gpgme_ctx_t ctx, int seq) +{ + unsigned int seqno; + + if (!ctx || seq < 0) + return NULL; + + seqno = (unsigned int) seq; + if (seqno >= ctx->signers_len) + return NULL; + gpgme_key_ref (ctx->signers[seqno]); + return ctx->signers[seqno]; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/status-table.h b/libkdenetwork/libgpgme-copy/gpgme/status-table.h new file mode 100644 index 000000000..e2ae5c3b6 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/status-table.h @@ -0,0 +1,94 @@ +/* Generated automatically by mkstatus */ +/* Do not edit! */ + +struct status_table_s { + const char *name; + gpgme_status_code_t code; +}; + +static struct status_table_s status_table[] = +{ + { "ABORT", GPGME_STATUS_ABORT }, + { "ALREADY_SIGNED", GPGME_STATUS_ALREADY_SIGNED }, + { "BACKUP_KEY_CREATED", GPGME_STATUS_BACKUP_KEY_CREATED }, + { "BADARMOR", GPGME_STATUS_BADARMOR }, + { "BADMDC", GPGME_STATUS_BADMDC }, + { "BADSIG", GPGME_STATUS_BADSIG }, + { "BAD_PASSPHRASE", GPGME_STATUS_BAD_PASSPHRASE }, + { "BEGIN_DECRYPTION", GPGME_STATUS_BEGIN_DECRYPTION }, + { "BEGIN_ENCRYPTION", GPGME_STATUS_BEGIN_ENCRYPTION }, + { "BEGIN_STREAM", GPGME_STATUS_BEGIN_STREAM }, + { "CARDCTRL", GPGME_STATUS_CARDCTRL }, + { "DECRYPTION_FAILED", GPGME_STATUS_DECRYPTION_FAILED }, + { "DECRYPTION_OKAY", GPGME_STATUS_DECRYPTION_OKAY }, + { "DELETE_PROBLEM", GPGME_STATUS_DELETE_PROBLEM }, + { "ENC_TO", GPGME_STATUS_ENC_TO }, + { "END_DECRYPTION", GPGME_STATUS_END_DECRYPTION }, + { "END_ENCRYPTION", GPGME_STATUS_END_ENCRYPTION }, + { "END_STREAM", GPGME_STATUS_END_STREAM }, + { "ENTER", GPGME_STATUS_ENTER }, + { "ERRMDC", GPGME_STATUS_ERRMDC }, + { "ERROR", GPGME_STATUS_ERROR }, + { "ERRSIG", GPGME_STATUS_ERRSIG }, + { "EXPKEYSIG", GPGME_STATUS_EXPKEYSIG }, + { "EXPSIG", GPGME_STATUS_EXPSIG }, + { "FILE_DONE", GPGME_STATUS_FILE_DONE }, + { "FILE_ERROR", GPGME_STATUS_FILE_ERROR }, + { "FILE_START", GPGME_STATUS_FILE_START }, + { "GET_BOOL", GPGME_STATUS_GET_BOOL }, + { "GET_HIDDEN", GPGME_STATUS_GET_HIDDEN }, + { "GET_LINE", GPGME_STATUS_GET_LINE }, + { "GOODMDC", GPGME_STATUS_GOODMDC }, + { "GOODSIG", GPGME_STATUS_GOODSIG }, + { "GOOD_PASSPHRASE", GPGME_STATUS_GOOD_PASSPHRASE }, + { "GOT_IT", GPGME_STATUS_GOT_IT }, + { "IMPORTED", GPGME_STATUS_IMPORTED }, + { "IMPORT_OK", GPGME_STATUS_IMPORT_OK }, + { "IMPORT_PROBLEM", GPGME_STATUS_IMPORT_PROBLEM }, + { "IMPORT_RES", GPGME_STATUS_IMPORT_RES }, + { "INV_RECP", GPGME_STATUS_INV_RECP }, + { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED }, + { "KEYREVOKED", GPGME_STATUS_KEYREVOKED }, + { "KEY_CREATED", GPGME_STATUS_KEY_CREATED }, + { "LEAVE", GPGME_STATUS_LEAVE }, + { "MISSING_PASSPHRASE", GPGME_STATUS_MISSING_PASSPHRASE }, + { "NEED_PASSPHRASE", GPGME_STATUS_NEED_PASSPHRASE }, + { "NEED_PASSPHRASE_PIN", GPGME_STATUS_NEED_PASSPHRASE_PIN }, + { "NEED_PASSPHRASE_SYM", GPGME_STATUS_NEED_PASSPHRASE_SYM }, + { "NEWSIG", GPGME_STATUS_NEWSIG }, + { "NODATA", GPGME_STATUS_NODATA }, + { "NOTATION_DATA", GPGME_STATUS_NOTATION_DATA }, + { "NOTATION_NAME", GPGME_STATUS_NOTATION_NAME }, + { "NO_PUBKEY", GPGME_STATUS_NO_PUBKEY }, + { "NO_RECP", GPGME_STATUS_NO_RECP }, + { "NO_SECKEY", GPGME_STATUS_NO_SECKEY }, + { "PKA_TRUST_BAD", GPGME_STATUS_PKA_TRUST_BAD }, + { "PKA_TRUST_GOOD", GPGME_STATUS_PKA_TRUST_GOOD }, + { "PLAINTEXT", GPGME_STATUS_PLAINTEXT }, + { "POLICY_URL", GPGME_STATUS_POLICY_URL }, + { "PROGRESS", GPGME_STATUS_PROGRESS }, + { "REVKEYSIG", GPGME_STATUS_REVKEYSIG }, + { "RSA_OR_IDEA", GPGME_STATUS_RSA_OR_IDEA }, + { "SC_OP_FAILURE", GPGME_STATUS_SC_OP_FAILURE }, + { "SC_OP_SUCCESS", GPGME_STATUS_SC_OP_SUCCESS }, + { "SESSION_KEY", GPGME_STATUS_SESSION_KEY }, + { "SHM_GET", GPGME_STATUS_SHM_GET }, + { "SHM_GET_BOOL", GPGME_STATUS_SHM_GET_BOOL }, + { "SHM_GET_HIDDEN", GPGME_STATUS_SHM_GET_HIDDEN }, + { "SHM_INFO", GPGME_STATUS_SHM_INFO }, + { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED }, + { "SIG_CREATED", GPGME_STATUS_SIG_CREATED }, + { "SIG_ID", GPGME_STATUS_SIG_ID }, + { "SIG_SUBPACKET", GPGME_STATUS_SIG_SUBPACKET }, + { "TRUNCATED", GPGME_STATUS_TRUNCATED }, + { "TRUST_FULLY", GPGME_STATUS_TRUST_FULLY }, + { "TRUST_MARGINAL", GPGME_STATUS_TRUST_MARGINAL }, + { "TRUST_NEVER", GPGME_STATUS_TRUST_NEVER }, + { "TRUST_ULTIMATE", GPGME_STATUS_TRUST_ULTIMATE }, + { "TRUST_UNDEFINED", GPGME_STATUS_TRUST_UNDEFINED }, + { "UNEXPECTED", GPGME_STATUS_UNEXPECTED }, + { "USERID_HINT", GPGME_STATUS_USERID_HINT }, + { "VALIDSIG", GPGME_STATUS_VALIDSIG }, + {NULL, 0} +}; + diff --git a/libkdenetwork/libgpgme-copy/gpgme/stpcpy.c b/libkdenetwork/libgpgme-copy/gpgme/stpcpy.c new file mode 100644 index 000000000..6e42911fd --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/stpcpy.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1992, 1995, 1997, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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. + + The GNU C Library 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 the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <string.h> + +#undef __stpcpy +#undef stpcpy + +#ifndef weak_alias +# define __stpcpy stpcpy +#endif + +/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ +char * +__stpcpy (dest, src) + char *dest; + const char *src; +{ + register char *d = dest; + register const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} +#ifdef libc_hidden_def +libc_hidden_def (__stpcpy) +#endif +#ifdef weak_alias +weak_alias (__stpcpy, stpcpy) +#endif +#ifdef libc_hidden_builtin_def +libc_hidden_builtin_def (stpcpy) +#endif diff --git a/libkdenetwork/libgpgme-copy/gpgme/trust-item.c b/libkdenetwork/libgpgme-copy/gpgme/trust-item.c new file mode 100644 index 000000000..4dd0c4e59 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/trust-item.c @@ -0,0 +1,171 @@ +/* trust-item.c - Trust item objects. + 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 <assert.h> +#include <errno.h> + +#include "util.h" +#include "ops.h" +#include "sema.h" + + +/* Protects all reference counters in trust items. All other accesses + to a trust item are either read only or happen before the trust + item is available to the user. */ +DEFINE_STATIC_LOCK (trust_item_ref_lock); + + +/* Create a new trust item. */ +gpgme_error_t +_gpgme_trust_item_new (gpgme_trust_item_t *r_item) +{ + gpgme_trust_item_t item; + + item = calloc (1, sizeof *item); + if (!item) + return gpg_error_from_errno (errno); + item->_refs = 1; + item->keyid = item->_keyid; + item->_keyid[16] = '\0'; + item->owner_trust = item->_owner_trust; + item->_owner_trust[1] = '\0'; + item->validity = item->_validity; + item->_validity[1] = '\0'; + *r_item = item; + return 0; +} + + +/* Acquire a reference to ITEM. */ +void +gpgme_trust_item_ref (gpgme_trust_item_t item) +{ + LOCK (trust_item_ref_lock); + item->_refs++; + UNLOCK (trust_item_ref_lock); +} + + +/* gpgme_trust_item_unref releases the trust item object. Note that + this function may not do an actual release if there are other + shallow copies of the object. You have to call this function for + every newly created trust item object as well as for every + gpgme_trust_item_ref() done on the trust item object. */ +void +gpgme_trust_item_unref (gpgme_trust_item_t item) +{ + LOCK (trust_item_ref_lock); + assert (item->_refs > 0); + if (--item->_refs) + { + UNLOCK (trust_item_ref_lock); + return; + } + UNLOCK (trust_item_ref_lock); + + if (item->name) + free (item->name); + free (item); +} + + +/* Compatibility interfaces. */ +void +gpgme_trust_item_release (gpgme_trust_item_t item) +{ + gpgme_trust_item_unref (item); +} + +/* Return the value of the attribute WHAT of ITEM, which has to be + representable by a string. */ +const char *gpgme_trust_item_get_string_attr (gpgme_trust_item_t item, + _gpgme_attr_t what, + const void *reserved, int idx) +{ + const char *val = NULL; + + if (!item) + return NULL; + if (reserved) + return NULL; + if (idx) + return NULL; + + switch (what) + { + case GPGME_ATTR_KEYID: + val = item->keyid; + break; + + case GPGME_ATTR_OTRUST: + val = item->owner_trust; + break; + + case GPGME_ATTR_VALIDITY: + val = item->validity; + break; + + case GPGME_ATTR_USERID: + val = item->name; + break; + + default: + break; + } + return val; +} + + +/* Return the value of the attribute WHAT of KEY, which has to be + representable by an integer. IDX specifies a running index if the + attribute appears more than once in the key. */ +int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what, + const void *reserved, int idx) +{ + int val = 0; + + if (!item) + return 0; + if (reserved) + return 0; + if (idx) + return 0; + + switch (what) + { + case GPGME_ATTR_LEVEL: + val = item->level; + break; + + case GPGME_ATTR_TYPE: + val = item->type; + break; + + default: + break; + } + return val; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/trustlist.c b/libkdenetwork/libgpgme-copy/gpgme/trustlist.c new file mode 100644 index 000000000..e8cdb66e5 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/trustlist.c @@ -0,0 +1,248 @@ +/* trustlist.c - Trust item listing. + 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 <assert.h> +#include <errno.h> + +#include "gpgme.h" +#include "util.h" +#include "context.h" +#include "ops.h" + + +struct trust_queue_item_s +{ + struct trust_queue_item_s *next; + gpgme_trust_item_t item; +}; + +typedef struct +{ + /* Something new is available. */ + int trust_cond; + struct trust_queue_item_s *trust_queue; +} *op_data_t; + + + +static gpgme_error_t +trustlist_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + return 0; +} + + +/* This handler is used to parse the output of --list-trust-path: + Format: + level:keyid:type:recno:ot:val:mc:cc:name: + With TYPE = U for a user ID + K for a key + The RECNO is either the one of the dir record or the one of the uid + record. OT is the the usual trust letter and only availabel on K + lines. VAL is the calcualted validity MC is the marginal trust + counter and only available on U lines CC is the same for the + complete count NAME ist the username and only printed on U + lines. */ +static gpgme_error_t +trustlist_colon_handler (void *priv, char *line) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + char *p, *pend; + int field = 0; + gpgme_trust_item_t item = NULL; + + if (!line) + return 0; /* EOF */ + + for (p = line; p; p = pend) + { + field++; + pend = strchr (p, ':'); + if (pend) + *pend++ = 0; + + switch (field) + { + case 1: /* level */ + err = _gpgme_trust_item_new (&item); + if (err) + return err; + item->level = atoi (p); + break; + case 2: /* long keyid */ + if (strlen (p) == DIM(item->keyid) - 1) + strcpy (item->keyid, p); + break; + case 3: /* type */ + item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0; + break; + case 5: /* owner trust */ + item->_owner_trust[0] = *p; + break; + case 6: /* validity */ + item->_validity[0] = *p; + break; + case 9: /* user ID */ + item->name = strdup (p); + if (!item->name) + { + int saved_errno = errno; + gpgme_trust_item_unref (item); + return gpg_error_from_errno (saved_errno); + } + break; + } + } + + if (item) + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item); + return 0; +} + + +void +_gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type, + void *type_data) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) data; + gpgme_error_t err; + void *hook; + op_data_t opd; + gpgme_trust_item_t item = (gpgme_trust_item_t) type_data; + struct trust_queue_item_s *q, *q2; + + assert (type == GPGME_EVENT_NEXT_TRUSTITEM); + + err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL); + opd = hook; + if (err) + return; + + q = malloc (sizeof *q); + if (!q) + { + gpgme_trust_item_unref (item); + /* FIXME: GPGME_Out_Of_Core; */ + return; + } + q->item = item; + q->next = NULL; + /* FIXME: Use a tail pointer */ + q2 = opd->trust_queue; + if (!q2) + opd->trust_queue = q; + else + { + while (q2->next) + q2 = q2->next; + q2->next = q; + } + /* FIXME: unlock queue */ + opd->trust_cond = 1; +} + + +gpgme_error_t +gpgme_op_trustlist_start (gpgme_ctx_t ctx, const char *pattern, int max_level) +{ + gpgme_error_t err = 0; + void *hook; + op_data_t opd; + + if (!pattern || !*pattern) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_reset (ctx, 2); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, + sizeof (*opd), NULL); + opd = hook; + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, + trustlist_status_handler, ctx); + err = _gpgme_engine_set_colon_line_handler (ctx->engine, + trustlist_colon_handler, ctx); + if (err) + return err; + + return _gpgme_engine_op_trustlist (ctx->engine, pattern); +} + + +gpgme_error_t +gpgme_op_trustlist_next (gpgme_ctx_t ctx, gpgme_trust_item_t *r_item) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + struct trust_queue_item_s *q; + + if (!r_item) + return gpg_error (GPG_ERR_INV_VALUE); + *r_item = NULL; + if (!ctx) + return gpg_error (GPG_ERR_INV_VALUE); + + err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL); + opd = hook; + if (err) + return err; + if (opd == NULL) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!opd->trust_queue) + { + err = _gpgme_wait_on_condition (ctx, &opd->trust_cond); + if (err) + return err; + if (!opd->trust_cond) + return gpg_error (GPG_ERR_EOF); + opd->trust_cond = 0; + assert (opd->trust_queue); + } + q = opd->trust_queue; + opd->trust_queue = q->next; + + *r_item = q->item; + free (q); + return 0; +} + + +/* Terminate a pending trustlist operation within CTX. */ +gpgme_error_t +gpgme_op_trustlist_end (gpgme_ctx_t ctx) +{ + if (!ctx) + return gpg_error (GPG_ERR_INV_VALUE); + + return 0; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/util.h b/libkdenetwork/libgpgme-copy/gpgme/util.h new file mode 100644 index 000000000..28d5e1922 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/util.h @@ -0,0 +1,106 @@ +/* util.h + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 UTIL_H +#define UTIL_H + +#include "gpgme.h" + + +#define DIM(v) (sizeof(v)/sizeof((v)[0])) + + +/*-- {posix,w32}-util.c --*/ +const char *_gpgme_get_gpg_path (void); +const char *_gpgme_get_gpgsm_path (void); +int _gpgme_get_conf_int (const char *key, int *value); + + +/*-- replacement functions in <funcname>.c --*/ +#ifdef HAVE_CONFIG_H + +#ifndef HAVE_STPCPY +static _GPGME_INLINE char * +_gpgme_stpcpy (char *a, const char *b) +{ + while (*b) + *a++ = *b++; + *a = 0; + return a; +} +#define stpcpy(a,b) _gpgme_stpcpy ((a), (b)) +#endif /*!HAVE_STPCPY*/ + +#if !HAVE_VASPRINTF +#include <stdarg.h> +int vasprintf (char **result, const char *format, va_list args); +int asprintf (char **result, const char *format, ...); +#endif + +#ifndef HAVE_TTYNAME_R +int ttyname_r (int fd, char *buf, size_t buflen); +#endif +#endif + + +/*-- conversion.c --*/ +/* Convert two hexadecimal digits from STR to the value they + represent. Returns -1 if one of the characters is not a + hexadecimal digit. */ +int _gpgme_hextobyte (const char *str); + +/* Decode the C formatted string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. */ +gpgme_error_t _gpgme_decode_c_string (const char *src, char **destp, + size_t len); + +/* Decode the percent escaped string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. 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); + + +/* Parse the string TIMESTAMP into a time_t. The string may either be + seconds since Epoch or in the ISO 8601 format like + "20390815T143012". Returns 0 for an empty string or seconds since + Epoch. Leading spaces are skipped. If ENDP is not NULL, it will + point to the next non-parsed character in TIMESTRING. */ +time_t _gpgme_parse_timestamp (const char *timestamp, char **endp); + + +gpgme_error_t _gpgme_map_gnupg_error (char *err); + + +/* Retrieve the environment variable NAME and return a copy of it in a + malloc()'ed buffer in *VALUE. If the environment variable is not + set, return NULL in *VALUE. */ +gpgme_error_t _gpgme_getenv (const char *name, char **value); + +#endif /* UTIL_H */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/vasprintf.c b/libkdenetwork/libgpgme-copy/gpgme/vasprintf.c new file mode 100644 index 000000000..77113a310 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/vasprintf.c @@ -0,0 +1,192 @@ +/* Like vsprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. + Copyright (C) 1994, 2002 Free Software Foundation, Inc. + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + + +#ifndef va_copy /* According to POSIX, va_copy is a macro. */ +#if defined (__GNUC__) && defined (__PPC__) \ + && (defined (_CALL_SYSV) || defined (_WIN32)) +#define va_copy(d, s) (*(d) = *(s)) +#elif defined (MUST_COPY_VA_BYVAL) +#define va_copy(d, s) ((d) = (s)) +#else +#define va_copy(d, s) memcpy ((d), (s), sizeof (va_list)) +#endif +#endif + + +#ifdef TEST +int global_total_width; +#endif + +static int int_vasprintf (char **, const char *, va_list *); + +static int +int_vasprintf (result, format, args) + char **result; + const char *format; + va_list *args; +{ + const char *p = format; + /* Add one to make sure that it is never zero, which might cause malloc + to return NULL. */ + int total_width = strlen (format) + 1; + va_list ap; + + va_copy (ap, *args); + + while (*p != '\0') + { + if (*p++ == '%') + { + while (strchr ("-+ #0", *p)) + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + if (*p == '.') + { + ++p; + if (*p == '*') + { + ++p; + total_width += abs (va_arg (ap, int)); + } + else + total_width += strtoul (p, (char **) &p, 10); + } + while (strchr ("hlL", *p)) + ++p; + /* Should be big enough for any format specifier except %s and floats. */ + total_width += 30; + switch (*p) + { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + (void) va_arg (ap, int); + break; + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + (void) va_arg (ap, double); + /* Since an ieee double can have an exponent of 307, we'll + make the buffer wide enough to cover the gross case. */ + total_width += 307; + break; + case 's': + { + char *tmp = va_arg (ap, char *); + if (tmp) + total_width += strlen (tmp); + else /* in case the vsprintf does prints a text */ + total_width += 25; /* e.g. "(null pointer reference)" */ + } + break; + case 'p': + case 'n': + (void) va_arg (ap, char *); + break; + } + p++; + } + } +#ifdef TEST + global_total_width = total_width; +#endif + *result = malloc (total_width); + if (*result != NULL) + return vsprintf (*result, format, *args); + else + return 0; +} + +int +vasprintf (result, format, args) + char **result; + const char *format; +#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) + _BSD_VA_LIST_ args; +#else + va_list args; +#endif +{ + return int_vasprintf (result, format, &args); +} + + +int +asprintf (char **buf, const char *fmt, ...) +{ + int status; + va_list ap; + + va_start (ap, fmt); + status = vasprintf (buf, fmt, ap); + va_end (ap); + return status; +} + + +#ifdef TEST +void +checkit (const char* format, ...) +{ + va_list args; + char *result; + + va_start (args, format); + vasprintf (&result, format, args); + if (strlen (result) < global_total_width) + printf ("PASS: "); + else + printf ("FAIL: "); + printf ("%d %s\n", global_total_width, result); +} + +int +main (void) +{ + checkit ("%d", 0x12345678); + checkit ("%200d", 5); + checkit ("%.300d", 6); + checkit ("%100.150d", 7); + checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ +777777777777777777333333333333366666666666622222222222777777777777733333"); + checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); +} +#endif /* TEST */ diff --git a/libkdenetwork/libgpgme-copy/gpgme/verify.c b/libkdenetwork/libgpgme-copy/gpgme/verify.c new file mode 100644 index 000000000..a9730e59e --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/verify.c @@ -0,0 +1,992 @@ +/* verify.c - Signature verification. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "gpgme.h" +#include "util.h" +#include "context.h" +#include "ops.h" + + +typedef struct +{ + struct _gpgme_op_verify_result result; + + gpgme_signature_t current_sig; + int did_prepare_new_sig; + int only_newsig_seen; + int plaintext_seen; +} *op_data_t; + + +static void +release_op_data (void *hook) +{ + op_data_t opd = (op_data_t) hook; + gpgme_signature_t sig = opd->result.signatures; + + while (sig) + { + gpgme_signature_t next = sig->next; + gpgme_sig_notation_t notation = sig->notations; + + while (notation) + { + gpgme_sig_notation_t next_nota = notation->next; + + _gpgme_sig_notation_free (notation); + notation = next_nota; + } + + if (sig->fpr) + free (sig->fpr); + if (sig->pka_address) + free (sig->pka_address); + free (sig); + sig = next; + } + + if (opd->result.file_name) + free (opd->result.file_name); +} + + +gpgme_verify_result_t +gpgme_op_verify_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + gpgme_error_t err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); + opd = hook; + if (err || !opd) + return NULL; + + return &opd->result; +} + + +/* Build a summary vector from RESULT. */ +static void +calc_sig_summary (gpgme_signature_t sig) +{ + unsigned long sum = 0; + + /* Calculate the red/green flag. */ + if (sig->validity == GPGME_VALIDITY_FULL + || sig->validity == GPGME_VALIDITY_ULTIMATE) + { + if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR + || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED + || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED) + sum |= GPGME_SIGSUM_GREEN; + } + else if (sig->validity == GPGME_VALIDITY_NEVER) + { + if (gpg_err_code (sig->status) == GPG_ERR_NO_ERROR + || gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED + || gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED) + sum |= GPGME_SIGSUM_RED; + } + else if (gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE) + sum |= GPGME_SIGSUM_RED; + + + /* FIXME: handle the case when key and message are expired. */ + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_SIG_EXPIRED: + sum |= GPGME_SIGSUM_SIG_EXPIRED; + break; + + case GPG_ERR_KEY_EXPIRED: + sum |= GPGME_SIGSUM_KEY_EXPIRED; + break; + + case GPG_ERR_NO_PUBKEY: + sum |= GPGME_SIGSUM_KEY_MISSING; + break; + + case GPG_ERR_BAD_SIGNATURE: + case GPG_ERR_NO_ERROR: + break; + + default: + sum |= GPGME_SIGSUM_SYS_ERROR; + break; + } + + /* Now look at the certain reason codes. */ + switch (gpg_err_code (sig->validity_reason)) + { + case GPG_ERR_CRL_TOO_OLD: + if (sig->validity == GPGME_VALIDITY_UNKNOWN) + sum |= GPGME_SIGSUM_CRL_TOO_OLD; + break; + + case GPG_ERR_CERT_REVOKED: + sum |= GPGME_SIGSUM_KEY_REVOKED; + break; + + default: + break; + } + + /* Check other flags. */ + if (sig->wrong_key_usage) + sum |= GPGME_SIGSUM_BAD_POLICY; + + /* Set the valid flag when the signature is unquestionable + valid. */ + if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN)) + sum |= GPGME_SIGSUM_VALID; + + sig->summary = sum; +} + + +static gpgme_error_t +prepare_new_sig (op_data_t opd) +{ + gpgme_signature_t sig; + + if (opd->only_newsig_seen && opd->current_sig) + { + /* We have only seen the NEWSIG status and nothing else - we + better skip this signature therefore and reuse it for the + next possible signature. */ + sig = opd->current_sig; + memset (sig, 0, sizeof *sig); + assert (opd->result.signatures == sig); + } + else + { + sig = calloc (1, sizeof (*sig)); + if (!sig) + return gpg_error_from_errno (errno); + if (!opd->result.signatures) + opd->result.signatures = sig; + if (opd->current_sig) + opd->current_sig->next = sig; + opd->current_sig = sig; + } + opd->did_prepare_new_sig = 1; + opd->only_newsig_seen = 0; + return 0; +} + +static gpgme_error_t +parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args) +{ + gpgme_signature_t sig; + char *end = strchr (args, ' '); + char *tail; + + if (end) + { + *end = '\0'; + end++; + } + + if (!opd->did_prepare_new_sig) + { + gpg_error_t err; + + err = prepare_new_sig (opd); + if (err) + return err; + } + assert (opd->did_prepare_new_sig); + opd->did_prepare_new_sig = 0; + + assert (opd->current_sig); + sig = opd->current_sig; + + /* FIXME: We should set the source of the state. */ + switch (code) + { + case GPGME_STATUS_GOODSIG: + sig->status = gpg_error (GPG_ERR_NO_ERROR); + break; + + case GPGME_STATUS_EXPSIG: + sig->status = gpg_error (GPG_ERR_SIG_EXPIRED); + break; + + case GPGME_STATUS_EXPKEYSIG: + sig->status = gpg_error (GPG_ERR_KEY_EXPIRED); + break; + + case GPGME_STATUS_BADSIG: + sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE); + break; + + case GPGME_STATUS_REVKEYSIG: + sig->status = gpg_error (GPG_ERR_CERT_REVOKED); + break; + + case GPGME_STATUS_ERRSIG: + /* Parse the pubkey algo. */ + if (!end) + goto parse_err_sig_fail; + errno = 0; + sig->pubkey_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + goto parse_err_sig_fail; + end = tail; + while (*end == ' ') + end++; + + /* Parse the hash algo. */ + if (!*end) + goto parse_err_sig_fail; + errno = 0; + sig->hash_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + goto parse_err_sig_fail; + end = tail; + while (*end == ' ') + end++; + + /* Skip the sig class. */ + end = strchr (end, ' '); + if (!end) + goto parse_err_sig_fail; + while (*end == ' ') + end++; + + /* Parse the timestamp. */ + sig->timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + while (*end == ' ') + end++; + + /* Parse the return code. */ + if (end[0] && (!end[1] || end[1] == ' ')) + { + switch (end[0]) + { + case '4': + sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + break; + + case '9': + sig->status = gpg_error (GPG_ERR_NO_PUBKEY); + break; + + default: + sig->status = gpg_error (GPG_ERR_GENERAL); + } + } + else + goto parse_err_sig_fail; + + goto parse_err_sig_ok; + + parse_err_sig_fail: + sig->status = gpg_error (GPG_ERR_GENERAL); + parse_err_sig_ok: + break; + + default: + return gpg_error (GPG_ERR_GENERAL); + } + + if (*args) + { + sig->fpr = strdup (args); + if (!sig->fpr) + return gpg_error_from_errno (errno); + } + return 0; +} + + +static gpgme_error_t +parse_valid_sig (gpgme_signature_t sig, char *args) +{ + char *end = strchr (args, ' '); + if (end) + { + *end = '\0'; + end++; + } + + if (!*args) + /* We require at least the fingerprint. */ + return gpg_error (GPG_ERR_GENERAL); + + if (sig->fpr) + free (sig->fpr); + sig->fpr = strdup (args); + if (!sig->fpr) + return gpg_error_from_errno (errno); + + /* Skip the creation date. */ + end = strchr (end, ' '); + if (end) + { + char *tail; + + sig->timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail); + if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' ')) + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + while (*end == ' ') + end++; + /* Skip the signature version. */ + end = strchr (end, ' '); + if (end) + { + while (*end == ' ') + end++; + + /* Skip the reserved field. */ + end = strchr (end, ' '); + if (end) + { + /* Parse the pubkey algo. */ + errno = 0; + sig->pubkey_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + + while (*end == ' ') + end++; + + if (*end) + { + /* Parse the hash algo. */ + + errno = 0; + sig->hash_algo = strtol (end, &tail, 0); + if (errno || end == tail || *tail != ' ') + return gpg_error (GPG_ERR_INV_ENGINE); + end = tail; + } + } + } + } + return 0; +} + + +static gpgme_error_t +parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + gpgme_sig_notation_t *lastp = &sig->notations; + gpgme_sig_notation_t notation = sig->notations; + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) + { + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->value) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (notation) + /* There is another notation name without data for the + previous one. The crypto backend misbehaves. */ + return gpg_error (GPG_ERR_INV_ENGINE); + + err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0); + if (err) + return err; + + if (code == GPGME_STATUS_NOTATION_NAME) + { + err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0); + if (err) + { + _gpgme_sig_notation_free (notation); + return err; + } + + notation->name_len = strlen (notation->name); + + /* FIXME: For now we fake the human-readable flag. The + critical flag can not be reported as it is not + provided. */ + notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE; + notation->human_readable = 1; + } + else + { + /* This is a policy URL. */ + + err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0); + if (err) + { + _gpgme_sig_notation_free (notation); + return err; + } + + notation->value_len = strlen (notation->value); + } + *lastp = notation; + } + else if (code == GPGME_STATUS_NOTATION_DATA) + { + int len = strlen (args) + 1; + char *dest; + + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->next) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (!notation || !notation->name) + /* There is notation data without a previous notation + name. The crypto backend misbehaves. */ + return gpg_error (GPG_ERR_INV_ENGINE); + + if (!notation->value) + { + dest = notation->value = malloc (len); + if (!dest) + return gpg_error_from_errno (errno); + } + else + { + int cur_len = strlen (notation->value); + dest = realloc (notation->value, len + strlen (notation->value)); + if (!dest) + return gpg_error_from_errno (errno); + notation->value = dest; + dest += cur_len; + } + + err = _gpgme_decode_percent_string (args, &dest, len, 0); + if (err) + return err; + + notation->value_len += strlen (dest); + } + else + return gpg_error (GPG_ERR_INV_ENGINE); + return 0; +} + + +static gpgme_error_t +parse_trust (gpgme_signature_t sig, gpgme_status_code_t code, char *args) +{ + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + switch (code) + { + case GPGME_STATUS_TRUST_UNDEFINED: + default: + sig->validity = GPGME_VALIDITY_UNKNOWN; + break; + + case GPGME_STATUS_TRUST_NEVER: + sig->validity = GPGME_VALIDITY_NEVER; + break; + + case GPGME_STATUS_TRUST_MARGINAL: + sig->validity = GPGME_VALIDITY_MARGINAL; + break; + + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: + sig->validity = GPGME_VALIDITY_FULL; + break; + } + + if (*args) + sig->validity_reason = _gpgme_map_gnupg_error (args); + else + sig->validity_reason = 0; + + return 0; +} + + +/* Parse an error status line and if SET_STATUS is true update the + result status as appropriate. With SET_STATUS being false, only + check for an error. */ +static gpgme_error_t +parse_error (gpgme_signature_t sig, char *args, int set_status) +{ + gpgme_error_t err; + char *where = strchr (args, ' '); + char *which; + + if (where) + { + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + } + else + return gpg_error (GPG_ERR_INV_ENGINE); + + err = _gpgme_map_gnupg_error (which); + + if (!strcmp (where, "proc_pkt.plaintext") + && gpg_err_code (err) == GPG_ERR_BAD_DATA) + { + /* This indicates a double plaintext. The only solid way to + handle this is by failing the oepration. */ + return gpg_error (GPG_ERR_BAD_DATA); + } + else if (!set_status) + ; + else if (!strcmp (where, "verify.findkey")) + sig->status = err; + else if (!strcmp (where, "verify.keyusage") + && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE) + sig->wrong_key_usage = 1; + + return 0; +} + + +gpgme_error_t +_gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) priv; + gpgme_error_t err; + void *hook; + op_data_t opd; + gpgme_signature_t sig; + char *end; + + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); + opd = hook; + if (err) + return err; + + sig = opd->current_sig; + + switch (code) + { + case GPGME_STATUS_NEWSIG: + if (sig) + calc_sig_summary (sig); + err = prepare_new_sig (opd); + opd->only_newsig_seen = 1; + return err; + + case GPGME_STATUS_GOODSIG: + case GPGME_STATUS_EXPSIG: + case GPGME_STATUS_EXPKEYSIG: + case GPGME_STATUS_BADSIG: + case GPGME_STATUS_ERRSIG: + case GPGME_STATUS_REVKEYSIG: + if (sig && !opd->did_prepare_new_sig) + calc_sig_summary (sig); + opd->only_newsig_seen = 0; + return parse_new_sig (opd, code, args); + + case GPGME_STATUS_VALIDSIG: + opd->only_newsig_seen = 0; + return sig ? parse_valid_sig (sig, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_NODATA: + opd->only_newsig_seen = 0; + if (!sig) + return gpg_error (GPG_ERR_NO_DATA); + sig->status = gpg_error (GPG_ERR_NO_DATA); + break; + + case GPGME_STATUS_UNEXPECTED: + opd->only_newsig_seen = 0; + if (!sig) + return gpg_error (GPG_ERR_GENERAL); + sig->status = gpg_error (GPG_ERR_NO_DATA); + break; + + case GPGME_STATUS_NOTATION_NAME: + case GPGME_STATUS_NOTATION_DATA: + case GPGME_STATUS_POLICY_URL: + opd->only_newsig_seen = 0; + return sig ? parse_notation (sig, code, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_TRUST_UNDEFINED: + case GPGME_STATUS_TRUST_NEVER: + case GPGME_STATUS_TRUST_MARGINAL: + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: + opd->only_newsig_seen = 0; + return sig ? parse_trust (sig, code, args) + : gpg_error (GPG_ERR_INV_ENGINE); + + case GPGME_STATUS_PKA_TRUST_BAD: + case GPGME_STATUS_PKA_TRUST_GOOD: + opd->only_newsig_seen = 0; + /* Check that we only get one of these status codes per + signature; if not the crypto backend misbehaves. */ + if (!sig || sig->pka_trust || sig->pka_address) + return gpg_error (GPG_ERR_INV_ENGINE); + sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1; + end = strchr (args, ' '); + if (end) + *end = 0; + sig->pka_address = strdup (args); + break; + + case GPGME_STATUS_ERROR: + opd->only_newsig_seen = 0; + /* Some error stati are informational, so we don't return an + error code if we are not ready to process this status. */ + return parse_error (sig, args, !!sig ); + + case GPGME_STATUS_EOF: + if (sig && !opd->did_prepare_new_sig) + calc_sig_summary (sig); + if (opd->only_newsig_seen && sig) + { + gpgme_signature_t sig2; + /* The last signature has no valid information - remove it + from the list. */ + assert (!sig->next); + if (sig == opd->result.signatures) + opd->result.signatures = NULL; + else + { + for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next) + if (sig2->next == sig) + { + sig2->next = NULL; + break; + } + } + /* Note that there is no need to release the members of SIG + because we won't be here if they have been set. */ + free (sig); + opd->current_sig = NULL; + } + opd->only_newsig_seen = 0; + break; + + case GPGME_STATUS_PLAINTEXT: + if (++opd->plaintext_seen > 1) + return gpg_error (GPG_ERR_BAD_DATA); + err = _gpgme_parse_plaintext (args, &opd->result.file_name); + if (err) + return err; + + default: + break; + } + return 0; +} + + +static gpgme_error_t +verify_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + gpgme_error_t err; + + err = _gpgme_progress_status_handler (priv, code, args); + if (!err) + err = _gpgme_verify_status_handler (priv, code, args); + return err; +} + + +gpgme_error_t +_gpgme_op_verify_init_result (gpgme_ctx_t ctx) +{ + void *hook; + op_data_t opd; + + return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, + sizeof (*opd), release_op_data); +} + + +static gpgme_error_t +verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig, + gpgme_data_t signed_text, gpgme_data_t plaintext) +{ + gpgme_error_t err; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_verify_init_result (ctx); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, verify_status_handler, ctx); + + if (!sig) + return gpg_error (GPG_ERR_NO_DATA); + if (!signed_text && !plaintext) + return gpg_error (GPG_ERR_INV_VALUE); + + return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_verify_start (gpgme_ctx_t ctx, gpgme_data_t sig, + gpgme_data_t signed_text, gpgme_data_t plaintext) +{ + return verify_start (ctx, 0, sig, signed_text, plaintext); +} + + +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ +gpgme_error_t +gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t signed_text, + gpgme_data_t plaintext) +{ + gpgme_error_t err; + + err = verify_start (ctx, 1, sig, signed_text, plaintext); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +/* Compatibility interfaces. */ + +/* Get the key used to create signature IDX in CTX and return it in + R_KEY. */ +gpgme_error_t +gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return gpg_error (GPG_ERR_EOF); + + return gpgme_get_key (ctx, sig->fpr, r_key, 0); +} + + +/* Retrieve the signature status of signature IDX in CTX after a + successful verify operation in R_STAT (if non-null). The creation + time stamp of the signature is returned in R_CREATED (if non-null). + The function returns a string containing the fingerprint. */ +const char * +gpgme_get_sig_status (gpgme_ctx_t ctx, int idx, + _gpgme_sig_stat_t *r_stat, time_t *r_created) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return NULL; + + if (r_stat) + { + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_NO_ERROR: + *r_stat = GPGME_SIG_STAT_GOOD; + break; + + case GPG_ERR_BAD_SIGNATURE: + *r_stat = GPGME_SIG_STAT_BAD; + break; + + case GPG_ERR_NO_PUBKEY: + *r_stat = GPGME_SIG_STAT_NOKEY; + break; + + case GPG_ERR_NO_DATA: + *r_stat = GPGME_SIG_STAT_NOSIG; + break; + + case GPG_ERR_SIG_EXPIRED: + *r_stat = GPGME_SIG_STAT_GOOD_EXP; + break; + + case GPG_ERR_KEY_EXPIRED: + *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY; + break; + + default: + *r_stat = GPGME_SIG_STAT_ERROR; + break; + } + } + if (r_created) + *r_created = sig->timestamp; + return sig->fpr; +} + + +/* Retrieve certain attributes of a signature. IDX is the index + number of the signature after a successful verify operation. WHAT + is an attribute where GPGME_ATTR_EXPIRE is probably the most useful + one. WHATIDX is to be passed as 0 for most attributes . */ +unsigned long +gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx, + _gpgme_attr_t what, int whatidx) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return 0; + + switch (what) + { + case GPGME_ATTR_CREATED: + return sig->timestamp; + + case GPGME_ATTR_EXPIRE: + return sig->exp_timestamp; + + case GPGME_ATTR_VALIDITY: + return (unsigned long) sig->validity; + + case GPGME_ATTR_SIG_STATUS: + switch (gpg_err_code (sig->status)) + { + case GPG_ERR_NO_ERROR: + return GPGME_SIG_STAT_GOOD; + + case GPG_ERR_BAD_SIGNATURE: + return GPGME_SIG_STAT_BAD; + + case GPG_ERR_NO_PUBKEY: + return GPGME_SIG_STAT_NOKEY; + + case GPG_ERR_NO_DATA: + return GPGME_SIG_STAT_NOSIG; + + case GPG_ERR_SIG_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXP; + + case GPG_ERR_KEY_EXPIRED: + return GPGME_SIG_STAT_GOOD_EXPKEY; + + default: + return GPGME_SIG_STAT_ERROR; + } + + case GPGME_ATTR_SIG_SUMMARY: + return sig->summary; + + default: + break; + } + return 0; +} + + +const char * +gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx, + _gpgme_attr_t what, int whatidx) +{ + gpgme_verify_result_t result; + gpgme_signature_t sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return NULL; + + switch (what) + { + case GPGME_ATTR_FPR: + return sig->fpr; + + case GPGME_ATTR_ERRTOK: + if (whatidx == 1) + return sig->wrong_key_usage ? "Wrong_Key_Usage" : ""; + else + return ""; + default: + break; + } + + return NULL; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/version.c b/libkdenetwork/libgpgme-copy/gpgme/version.c new file mode 100644 index 000000000..a54c0d4da --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/version.c @@ -0,0 +1,231 @@ +/* version.c - Version check routines. + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <string.h> +#include <limits.h> +#include <ctype.h> + +#include "gpgme.h" +#include "priv-io.h" + +/* For _gpgme_sema_subsystem_init (). */ +#include "sema.h" + +#ifdef HAVE_ASSUAN_H +#include "assuan.h" +#endif + + +/* Bootstrap the subsystems needed for concurrent operation. This + must be done once at startup. We can not guarantee this using a + lock, though, because the semaphore subsystem needs to be + initialized itself before it can be used. So we expect that the + user performs the necessary syncrhonization. */ +static void +do_subsystem_inits (void) +{ + static int done = 0; + + if (done) + return; + + _gpgme_sema_subsystem_init (); + _gpgme_io_subsystem_init (); +#ifdef HAVE_ASSUAN_H + assuan_set_assuan_err_source (GPG_ERR_SOURCE_GPGME); +#endif + + done = 1; +} + + +/* Read the next number in the version string STR and return it in + *NUMBER. Return a pointer to the tail of STR after parsing, or + *NULL if the version string was invalid. */ +static const char * +parse_version_number (const char *str, int *number) +{ +#define MAXVAL ((INT_MAX - 10) / 10) + int val = 0; + + /* Leading zeros are not allowed. */ + if (*str == '0' && isdigit(str[1])) + return NULL; + + while (isdigit (*str) && val <= MAXVAL) + { + val *= 10; + val += *(str++) - '0'; + } + *number = val; + return val > MAXVAL ? NULL : str; +} + + +/* Parse the version string STR in the format MAJOR.MINOR.MICRO (for + example, 9.3.2) and return the components in MAJOR, MINOR and MICRO + as integers. The function returns the tail of the string that + follows the version number. This might be te empty string if there + is nothing following the version number, or a patchlevel. The + function returns NULL if the version string is not valid. */ +static const char * +parse_version_string (const char *str, int *major, int *minor, int *micro) +{ + str = parse_version_number (str, major); + if (!str || *str != '.') + return NULL; + str++; + + str = parse_version_number (str, minor); + if (!str || *str != '.') + return NULL; + str++; + + str = parse_version_number (str, micro); + if (!str) + return NULL; + + /* A patchlevel might follow. */ + return str; +} + + +/* Return true if MY_VERSION is at least REQ_VERSION, and false + otherwise. */ +int +_gpgme_compare_versions (const char *my_version, + const char *rq_version) +{ + int my_major, my_minor, my_micro; + int rq_major, rq_minor, rq_micro; + const char *my_plvl, *rq_plvl; + + if (!rq_version) + return 1; + if (!my_version) + return 0; + + my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro); + if (!my_plvl) + return 0; + + rq_plvl = parse_version_string (rq_version, &rq_major, &rq_minor, &rq_micro); + if (!rq_plvl) + return 0; + + if (my_major > rq_major + || (my_major == rq_major && my_minor > rq_minor) + || (my_major == rq_major && my_minor == rq_minor + && my_micro > rq_micro) + || (my_major == rq_major && my_minor == rq_minor + && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0)) + return 1; + + return 0; +} + + +/* Check that the the version of the library is at minimum the + requested one and return the version string; return NULL if the + condition is not met. If a NULL is passed to this function, no + check is done and the version string is simply returned. + + This function must be run once at startup, as it also initializes + some subsystems. Its invocation must be synchronized against + calling any of the other functions in a multi-threaded + environments. */ +const char * +gpgme_check_version (const char *req_version) +{ + do_subsystem_inits (); + return _gpgme_compare_versions (VERSION, req_version) ? VERSION : NULL; +} + + +#define LINELENGTH 80 + +/* Retrieve the version number from the --version output of the + program FILE_NAME. */ +char * +_gpgme_get_program_version (const char *const file_name) +{ + char line[LINELENGTH] = ""; + int linelen = 0; + char *mark = NULL; + int rp[2]; + int nread; + char *argv[] = {NULL /* file_name */, "--version", 0}; + struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} }; + struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} }; + int status; + + if (!file_name) + return NULL; + argv[0] = (char *) file_name; + + if (_gpgme_io_pipe (rp, 1) < 0) + return NULL; + + pfd[0].fd = rp[1]; + cfd[0].fd = rp[1]; + + status = _gpgme_io_spawn (file_name, argv, cfd, pfd); + if (status < 0) + { + _gpgme_io_close (rp[0]); + _gpgme_io_close (rp[1]); + return NULL; + } + + do + { + nread = _gpgme_io_read (rp[0], &line[linelen], LINELENGTH - linelen - 1); + if (nread > 0) + { + line[linelen + nread] = '\0'; + mark = strchr (&line[linelen], '\n'); + if (mark) + { + if (mark > &line[0] && *mark == '\r') + mark--; + *mark = '\0'; + break; + } + linelen += nread; + } + } + while (nread > 0 && linelen < LINELENGTH - 1); + + _gpgme_io_close (rp[0]); + + if (mark) + { + mark = strrchr (line, ' '); + if (!mark) + return NULL; + return strdup (mark + 1); + } + + return NULL; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/w32-io.c b/libkdenetwork/libgpgme-copy/gpgme/w32-io.c new file mode 100644 index 000000000..fd53a6fbc --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/w32-io.c @@ -0,0 +1,1152 @@ +/* w32-io.c - W32 API I/O 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <windows.h> +#include <io.h> + +#include "util.h" +#include "sema.h" +#include "priv-io.h" +#include "debug.h" + +/* We assume that a HANDLE can be represented by an int which should + be true for all i386 systems (HANDLE is defined as void *) and + these are the only systems for which Windows is available. Further + we assume that -1 denotes an invalid handle. */ + +#define fd_to_handle(a) ((HANDLE)(a)) +#define handle_to_fd(a) ((int)(a)) +#define pid_to_handle(a) ((HANDLE)(a)) +#define handle_to_pid(a) ((int)(a)) + +#define READBUF_SIZE 4096 +#define WRITEBUF_SIZE 4096 +#define PIPEBUF_SIZE 4096 +#define MAX_READERS 20 +#define MAX_WRITERS 20 + +static struct { + int inuse; + int fd; + void (*handler)(int,void*); + void *value; +} notify_table[256]; +DEFINE_STATIC_LOCK (notify_table_lock); + + +struct reader_context_s { + HANDLE file_hd; + HANDLE thread_hd; + DECLARE_LOCK (mutex); + + int stop_me; + int eof; + int eof_shortcut; + int error; + int error_code; + + HANDLE have_data_ev; /* manually reset */ + HANDLE have_space_ev; /* auto reset */ + HANDLE stopped; + size_t readpos, writepos; + char buffer[READBUF_SIZE]; +}; + + +static struct { + volatile int used; + int fd; + struct reader_context_s *context; +} reader_table[MAX_READERS]; +static int reader_table_size= MAX_READERS; +DEFINE_STATIC_LOCK (reader_table_lock); + + +struct writer_context_s { + HANDLE file_hd; + HANDLE thread_hd; + DECLARE_LOCK (mutex); + + int stop_me; + int error; + int error_code; + + HANDLE have_data; /* manually reset */ + HANDLE is_empty; + HANDLE stopped; + size_t nbytes; + char buffer[WRITEBUF_SIZE]; +}; + + +static struct { + volatile int used; + int fd; + struct writer_context_s *context; +} writer_table[MAX_WRITERS]; +static int writer_table_size= MAX_WRITERS; +DEFINE_STATIC_LOCK (writer_table_lock); + + + +static int +get_desired_thread_priority (void) +{ + int value; + + if (!_gpgme_get_conf_int ("IOThreadPriority", &value)) + { + value = THREAD_PRIORITY_HIGHEST; + DEBUG1 ("** Using standard IOThreadPriority of %d\n", value); + } + else + DEBUG1 ("** Configured IOThreadPriority is %d\n", value); + + return value; +} + + +static HANDLE +set_synchronize (HANDLE h) +{ + HANDLE tmp; + + /* For NT we have to set the sync flag. It seems that the only + * way to do it is by duplicating the handle. Tsss.. */ + if (!DuplicateHandle( GetCurrentProcess(), h, + GetCurrentProcess(), &tmp, + EVENT_MODIFY_STATE|SYNCHRONIZE, FALSE, 0 ) ) { + DEBUG1 ("** Set SYNCRONIZE failed: ec=%d\n", (int)GetLastError()); + } + else { + CloseHandle (h); + h = tmp; + } + return h; +} + + + +static DWORD CALLBACK +reader (void *arg) +{ + struct reader_context_s *c = arg; + int nbytes; + DWORD nread; + + DEBUG2 ("reader thread %p for file %p started", c->thread_hd, c->file_hd ); + for (;;) { + LOCK (c->mutex); + /* leave a 1 byte gap so that we can see whether it is empty or full*/ + if ((c->writepos + 1) % READBUF_SIZE == c->readpos) { + /* wait for space */ + if (!ResetEvent (c->have_space_ev) ) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + DEBUG1 ("reader thread %p: waiting for space ...", c->thread_hd ); + WaitForSingleObject (c->have_space_ev, INFINITE); + DEBUG1 ("reader thread %p: got space", c->thread_hd ); + LOCK (c->mutex); + } + if ( c->stop_me ) { + UNLOCK (c->mutex); + break; + } + nbytes = (c->readpos + READBUF_SIZE - c->writepos-1) % READBUF_SIZE; + if ( nbytes > READBUF_SIZE - c->writepos ) + nbytes = READBUF_SIZE - c->writepos; + UNLOCK (c->mutex); + + DEBUG2 ("reader thread %p: reading %d bytes", c->thread_hd, nbytes ); + if ( !ReadFile ( c->file_hd, + c->buffer+c->writepos, nbytes, &nread, NULL) ) { + c->error_code = (int)GetLastError (); + if (c->error_code == ERROR_BROKEN_PIPE ) { + c->eof=1; + DEBUG1 ("reader thread %p: got eof (broken pipe)", + c->thread_hd ); + } + else { + c->error = 1; + DEBUG2 ("reader thread %p: read error: ec=%d", + c->thread_hd, c->error_code ); + } + break; + } + if ( !nread ) { + c->eof = 1; + DEBUG1 ("reader thread %p: got eof", c->thread_hd ); + break; + } + DEBUG2 ("reader thread %p: got %d bytes", c->thread_hd, (int)nread ); + + LOCK (c->mutex); + if (c->stop_me) { + UNLOCK (c->mutex); + break; + } + c->writepos = (c->writepos + nread) % READBUF_SIZE; + if ( !SetEvent (c->have_data_ev) ) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + } + /* indicate that we have an error or eof */ + if ( !SetEvent (c->have_data_ev) ) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + DEBUG1 ("reader thread %p ended", c->thread_hd ); + SetEvent (c->stopped); + + return 0; +} + + +static struct reader_context_s * +create_reader (HANDLE fd) +{ + struct reader_context_s *c; + SECURITY_ATTRIBUTES sec_attr; + DWORD tid; + + DEBUG1 ("creating new read thread for file handle %p", fd ); + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + c = calloc (1, sizeof *c ); + if (!c) + return NULL; + + c->file_hd = fd; + c->have_data_ev = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + c->have_space_ev = CreateEvent (&sec_attr, FALSE, TRUE, NULL); + c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (!c->have_data_ev || !c->have_space_ev || !c->stopped ) { + DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ()); + if (c->have_data_ev) + CloseHandle (c->have_data_ev); + if (c->have_space_ev) + CloseHandle (c->have_space_ev); + if (c->stopped) + CloseHandle (c->stopped); + free (c); + return NULL; + } + + c->have_data_ev = set_synchronize (c->have_data_ev); + INIT_LOCK (c->mutex); + + c->thread_hd = CreateThread (&sec_attr, 0, reader, c, 0, &tid ); + if (!c->thread_hd) { + DEBUG1 ("** failed to create reader thread: ec=%d\n", + (int)GetLastError ()); + DESTROY_LOCK (c->mutex); + if (c->have_data_ev) + CloseHandle (c->have_data_ev); + if (c->have_space_ev) + CloseHandle (c->have_space_ev); + if (c->stopped) + CloseHandle (c->stopped); + free (c); + return NULL; + } + else { + /* We set the priority of the thread higher because we know that + it only runs for a short time. This greatly helps to increase + the performance of the I/O. */ + SetThreadPriority (c->thread_hd, get_desired_thread_priority ()); + } + + return c; +} + +static void +destroy_reader (struct reader_context_s *c) +{ + LOCK (c->mutex); + c->stop_me = 1; + if (c->have_space_ev) + SetEvent (c->have_space_ev); + UNLOCK (c->mutex); + + DEBUG1 ("waiting for thread %p termination ...", c->thread_hd ); + WaitForSingleObject (c->stopped, INFINITE); + DEBUG1 ("thread %p has terminated", c->thread_hd ); + + if (c->stopped) + CloseHandle (c->stopped); + if (c->have_data_ev) + CloseHandle (c->have_data_ev); + if (c->have_space_ev) + CloseHandle (c->have_space_ev); + CloseHandle (c->thread_hd); + DESTROY_LOCK (c->mutex); + free (c); +} + + +/* + * Find a reader context or create a new one + * Note that the reader context will last until a io_close. + */ +static struct reader_context_s * +find_reader (int fd, int start_it) +{ + int i; + + for (i=0; i < reader_table_size ; i++ ) { + if ( reader_table[i].used && reader_table[i].fd == fd ) + return reader_table[i].context; + } + if (!start_it) + return NULL; + + LOCK (reader_table_lock); + for (i=0; i < reader_table_size; i++ ) { + if (!reader_table[i].used) { + reader_table[i].fd = fd; + reader_table[i].context = create_reader (fd_to_handle (fd)); + reader_table[i].used = 1; + UNLOCK (reader_table_lock); + return reader_table[i].context; + } + } + UNLOCK (reader_table_lock); + return NULL; +} + + +static void +kill_reader (int fd) +{ + int i; + + LOCK (reader_table_lock); + for (i=0; i < reader_table_size; i++ ) { + if (reader_table[i].used && reader_table[i].fd == fd ) { + destroy_reader (reader_table[i].context); + reader_table[i].context = NULL; + reader_table[i].used = 0; + break; + } + } + UNLOCK (reader_table_lock); +} + + + +int +_gpgme_io_read ( int fd, void *buffer, size_t count ) +{ + int nread; + struct reader_context_s *c = find_reader (fd,1); + + DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int)count ); + if ( !c ) { + DEBUG0 ( "no reader thread\n"); + return -1; + } + if (c->eof_shortcut) { + DEBUG1 ("fd %d: EOF (again)", fd ); + return 0; + } + + LOCK (c->mutex); + if (c->readpos == c->writepos && !c->error) { /*no data avail*/ + UNLOCK (c->mutex); + DEBUG2 ("fd %d: waiting for data from thread %p", fd, c->thread_hd); + WaitForSingleObject (c->have_data_ev, INFINITE); + DEBUG2 ("fd %d: data from thread %p available", fd, c->thread_hd); + LOCK (c->mutex); + } + + if (c->readpos == c->writepos || c->error) { + UNLOCK (c->mutex); + c->eof_shortcut = 1; + if (c->eof) { + DEBUG1 ("fd %d: EOF", fd ); + return 0; + } + if (!c->error) { + DEBUG1 ("fd %d: EOF but eof flag not set", fd ); + return 0; + } + DEBUG1 ("fd %d: read error", fd ); + return -1; + } + + nread = c->readpos < c->writepos? c->writepos - c->readpos + : READBUF_SIZE - c->readpos; + if (nread > count) + nread = count; + memcpy (buffer, c->buffer+c->readpos, nread); + c->readpos = (c->readpos + nread) % READBUF_SIZE; + if (c->readpos == c->writepos && !c->eof) { + if ( !ResetEvent (c->have_data_ev) ) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); + } + if (!SetEvent (c->have_space_ev)) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + + DEBUG2 ("fd %d: got %d bytes\n", fd, nread ); + if (nread > 0) + _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer); + + return nread; +} +/* + * The writer does use a simple buffering strategy so that we are + * informed about write errors as soon as possible (i.e. with the the + * next call to the write function + */ +static DWORD CALLBACK +writer (void *arg) +{ + struct writer_context_s *c = arg; + DWORD nwritten; + + DEBUG2 ("writer thread %p for file %p started", c->thread_hd, c->file_hd ); + for (;;) { + LOCK (c->mutex); + if ( c->stop_me ) { + UNLOCK (c->mutex); + break; + } + if ( !c->nbytes ) { + if (!SetEvent (c->is_empty)) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + if (!ResetEvent (c->have_data) ) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + DEBUG1 ("writer thread %p: idle ...", c->thread_hd ); + WaitForSingleObject (c->have_data, INFINITE); + DEBUG1 ("writer thread %p: got data to send", c->thread_hd ); + LOCK (c->mutex); + } + if ( c->stop_me ) { + UNLOCK (c->mutex); + break; + } + UNLOCK (c->mutex); + + DEBUG2 ("writer thread %p: writing %d bytes", + c->thread_hd, c->nbytes ); + if ( c->nbytes && !WriteFile ( c->file_hd, c->buffer, c->nbytes, + &nwritten, NULL)) { + c->error_code = (int)GetLastError (); + c->error = 1; + DEBUG2 ("writer thread %p: write error: ec=%d", + c->thread_hd, c->error_code ); + break; + } + DEBUG2 ("writer thread %p: wrote %d bytes", + c->thread_hd, (int)nwritten ); + + LOCK (c->mutex); + c->nbytes -= nwritten; + UNLOCK (c->mutex); + } + /* indicate that we have an error */ + if ( !SetEvent (c->is_empty) ) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + DEBUG1 ("writer thread %p ended", c->thread_hd ); + SetEvent (c->stopped); + + return 0; +} + + +static struct writer_context_s * +create_writer (HANDLE fd) +{ + struct writer_context_s *c; + SECURITY_ATTRIBUTES sec_attr; + DWORD tid; + + DEBUG1 ("creating new write thread for file handle %p", fd ); + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + c = calloc (1, sizeof *c ); + if (!c) + return NULL; + + c->file_hd = fd; + c->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + c->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL); + c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL); + if (!c->have_data || !c->is_empty || !c->stopped ) { + DEBUG1 ("** CreateEvent failed: ec=%d\n", (int)GetLastError ()); + if (c->have_data) + CloseHandle (c->have_data); + if (c->is_empty) + CloseHandle (c->is_empty); + if (c->stopped) + CloseHandle (c->stopped); + free (c); + return NULL; + } + + c->is_empty = set_synchronize (c->is_empty); + INIT_LOCK (c->mutex); + + c->thread_hd = CreateThread (&sec_attr, 0, writer, c, 0, &tid ); + if (!c->thread_hd) { + DEBUG1 ("** failed to create writer thread: ec=%d\n", + (int)GetLastError ()); + DESTROY_LOCK (c->mutex); + if (c->have_data) + CloseHandle (c->have_data); + if (c->is_empty) + CloseHandle (c->is_empty); + if (c->stopped) + CloseHandle (c->stopped); + free (c); + return NULL; + } + else { + /* We set the priority of the thread higher because we know that + it only runs for a short time. This greatly helps to increase + the performance of the I/O. */ + SetThreadPriority (c->thread_hd, get_desired_thread_priority ()); + } + + return c; +} + +static void +destroy_writer (struct writer_context_s *c) +{ + LOCK (c->mutex); + c->stop_me = 1; + if (c->have_data) + SetEvent (c->have_data); + UNLOCK (c->mutex); + + DEBUG1 ("waiting for thread %p termination ...", c->thread_hd ); + WaitForSingleObject (c->stopped, INFINITE); + DEBUG1 ("thread %p has terminated", c->thread_hd ); + + if (c->stopped) + CloseHandle (c->stopped); + if (c->have_data) + CloseHandle (c->have_data); + if (c->is_empty) + CloseHandle (c->is_empty); + CloseHandle (c->thread_hd); + DESTROY_LOCK (c->mutex); + free (c); +} + + +/* + * Find a writer context or create a new one + * Note that the writer context will last until a io_close. + */ +static struct writer_context_s * +find_writer (int fd, int start_it) +{ + int i; + + for (i=0; i < writer_table_size ; i++ ) { + if ( writer_table[i].used && writer_table[i].fd == fd ) + return writer_table[i].context; + } + if (!start_it) + return NULL; + + LOCK (writer_table_lock); + for (i=0; i < writer_table_size; i++ ) { + if (!writer_table[i].used) { + writer_table[i].fd = fd; + writer_table[i].context = create_writer (fd_to_handle (fd)); + writer_table[i].used = 1; + UNLOCK (writer_table_lock); + return writer_table[i].context; + } + } + UNLOCK (writer_table_lock); + return NULL; +} + + +static void +kill_writer (int fd) +{ + int i; + + LOCK (writer_table_lock); + for (i=0; i < writer_table_size; i++ ) { + if (writer_table[i].used && writer_table[i].fd == fd ) { + destroy_writer (writer_table[i].context); + writer_table[i].context = NULL; + writer_table[i].used = 0; + break; + } + } + UNLOCK (writer_table_lock); +} + + + + +int +_gpgme_io_write ( int fd, const void *buffer, size_t count ) +{ + struct writer_context_s *c = find_writer (fd,1); + + DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int)count ); + _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer); + if ( !c ) { + DEBUG0 ( "no writer thread\n"); + return -1; + } + + LOCK (c->mutex); + if ( c->nbytes ) { /* bytes are pending for send */ + /* Reset the is_empty event. Better safe than sorry. */ + if (!ResetEvent (c->is_empty)) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + DEBUG2 ("fd %d: waiting for empty buffer in thread %p", + fd, c->thread_hd); + WaitForSingleObject (c->is_empty, INFINITE); + DEBUG2 ("fd %d: thread %p buffer is empty", fd, c->thread_hd); + LOCK (c->mutex); + } + + if ( c->error) { + UNLOCK (c->mutex); + DEBUG1 ("fd %d: write error", fd ); + return -1; + } + + /* If no error occured, the number of bytes in the buffer must be + zero. */ + assert (!c->nbytes); + + if (count > WRITEBUF_SIZE) + count = WRITEBUF_SIZE; + memcpy (c->buffer, buffer, count); + c->nbytes = count; + + /* We have to reset the is_empty event early, because it is also + used by the select() implementation to probe the channel. */ + if (!ResetEvent (c->is_empty)) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); + if (!SetEvent (c->have_data)) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); + UNLOCK (c->mutex); + + DEBUG2 ("fd %d: copied %d bytes\n", + fd, (int)count ); + return (int)count; +} + + +int +_gpgme_io_pipe ( int filedes[2], int inherit_idx ) +{ + HANDLE r, w; + SECURITY_ATTRIBUTES sec_attr; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + if (!CreatePipe ( &r, &w, &sec_attr, PIPEBUF_SIZE)) + return -1; + /* Make one end inheritable. */ + if ( inherit_idx == 0 ) { + HANDLE h; + if (!DuplicateHandle( GetCurrentProcess(), r, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS ) ) { + DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError()); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (r); + r = h; + } + else if ( inherit_idx == 1 ) { + HANDLE h; + if (!DuplicateHandle( GetCurrentProcess(), w, + GetCurrentProcess(), &h, 0, + TRUE, DUPLICATE_SAME_ACCESS ) ) { + DEBUG1 ("DuplicateHandle failed: ec=%d\n", (int)GetLastError()); + CloseHandle (r); + CloseHandle (w); + return -1; + } + CloseHandle (w); + w = h; + } + + filedes[0] = handle_to_fd (r); + filedes[1] = handle_to_fd (w); + DEBUG5 ("CreatePipe %p %p %d %d inherit=%d\n", r, w, + filedes[0], filedes[1], inherit_idx ); + return 0; +} + +int +_gpgme_io_close ( int fd ) +{ + int i; + void (*handler)(int, void*) = NULL; + void *value = NULL; + + if ( fd == -1 ) + return -1; + + DEBUG1 ("** closing handle for fd %d\n", fd); + kill_reader (fd); + kill_writer (fd); + LOCK (notify_table_lock); + for ( i=0; i < DIM (notify_table); i++ ) { + if (notify_table[i].inuse && notify_table[i].fd == fd) { + handler = notify_table[i].handler; + value = notify_table[i].value; + notify_table[i].handler = NULL; + notify_table[i].value = NULL; + notify_table[i].inuse = 0; + break; + } + } + UNLOCK (notify_table_lock); + if (handler) + handler (fd, value); + + if ( !CloseHandle (fd_to_handle (fd)) ) { + DEBUG2 ("CloseHandle for fd %d failed: ec=%d\n", + fd, (int)GetLastError ()); + return -1; + } + + return 0; +} + +int +_gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value) +{ + int i; + + assert (fd != -1); + + LOCK (notify_table_lock); + for (i=0; i < DIM (notify_table); i++ ) { + if ( notify_table[i].inuse && notify_table[i].fd == fd ) + break; + } + if ( i == DIM (notify_table) ) { + for (i=0; i < DIM (notify_table); i++ ) { + if ( !notify_table[i].inuse ) + break; + } + } + if ( i == DIM (notify_table) ) { + UNLOCK (notify_table_lock); + return -1; + } + notify_table[i].fd = fd; + notify_table[i].handler = handler; + notify_table[i].value = value; + notify_table[i].inuse = 1; + UNLOCK (notify_table_lock); + DEBUG2 ("set notification for fd %d (idx=%d)", fd, i ); + return 0; +} + + +int +_gpgme_io_set_nonblocking ( int fd ) +{ + return 0; +} + + +static char * +build_commandline (char **argv) +{ + int i; + int j; + int n = 0; + char *buf; + char *p; + + /* We have to quote some things because under Windows the program + parses the commandline and does some unquoting. We enclose the + whole argument in double-quotes, and escape literal double-quotes + as well as backslashes with a backslash. We end up with a + trailing space at the end of the line, but that is harmless. */ + for (i = 0; argv[i]; i++) + { + p = argv[i]; + /* The leading double-quote. */ + n++; + while (*p) + { + /* An extra one for each literal that must be escaped. */ + if (*p == '\\' || *p == '"') + n++; + n++; + p++; + } + /* The trailing double-quote and the delimiter. */ + n += 2; + } + /* And a trailing zero. */ + n++; + + buf = p = malloc (n); + if (!buf) + return NULL; + for (i = 0; argv[i]; i++) + { + char *argvp = argv[i]; + + *(p++) = '"'; + while (*argvp) + { + if (*argvp == '\\' || *argvp == '"') + *(p++) = '\\'; + *(p++) = *(argvp++); + } + *(p++) = '"'; + *(p++) = ' '; + } + *(p++) = 0; + + return buf; +} + + +int +_gpgme_io_spawn ( const char *path, char **argv, + struct spawn_fd_item_s *fd_child_list, + struct spawn_fd_item_s *fd_parent_list ) +{ + SECURITY_ATTRIBUTES sec_attr; + PROCESS_INFORMATION pi = { + NULL, /* returns process handle */ + 0, /* returns primary thread handle */ + 0, /* returns pid */ + 0 /* returns tid */ + }; + STARTUPINFO si; + char *envblock = NULL; + int cr_flags = CREATE_DEFAULT_ERROR_MODE + | GetPriorityClass (GetCurrentProcess ()); + int i; + char *arg_string; + int duped_stdin = 0; + int duped_stderr = 0; + HANDLE hnul = INVALID_HANDLE_VALUE; + /* FIXME. */ + int debug_me = 0; + + memset (&sec_attr, 0, sizeof sec_attr ); + sec_attr.nLength = sizeof sec_attr; + sec_attr.bInheritHandle = FALSE; + + arg_string = build_commandline ( argv ); + if (!arg_string ) + return -1; + + memset (&si, 0, sizeof si); + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = debug_me? SW_SHOW : SW_HIDE; + si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); + si.hStdError = GetStdHandle (STD_ERROR_HANDLE); + + for (i=0; fd_child_list[i].fd != -1; i++ ) { + if (fd_child_list[i].dup_to == 0 ) { + si.hStdInput = fd_to_handle (fd_child_list[i].fd); + DEBUG1 ("using %d for stdin", fd_child_list[i].fd ); + duped_stdin=1; + } + else if (fd_child_list[i].dup_to == 1 ) { + si.hStdOutput = fd_to_handle (fd_child_list[i].fd); + DEBUG1 ("using %d for stdout", fd_child_list[i].fd ); + } + else if (fd_child_list[i].dup_to == 2 ) { + si.hStdError = fd_to_handle (fd_child_list[i].fd); + DEBUG1 ("using %d for stderr", fd_child_list[i].fd ); + duped_stderr = 1; + } + } + + if( !duped_stdin || !duped_stderr ) { + SECURITY_ATTRIBUTES sa; + + memset (&sa, 0, sizeof sa ); + sa.nLength = sizeof sa; + sa.bInheritHandle = TRUE; + hnul = CreateFile ( "nul", + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, + &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + if ( hnul == INVALID_HANDLE_VALUE ) { + DEBUG1 ("can't open `nul': ec=%d\n", (int)GetLastError ()); + free (arg_string); + return -1; + } + /* Make sure that the process has a connected stdin */ + if ( !duped_stdin ) { + si.hStdInput = hnul; + DEBUG1 ("using %d for dummy stdin", (int)hnul ); + } + /* We normally don't want all the normal output */ + if ( !duped_stderr ) { + si.hStdError = hnul; + DEBUG1 ("using %d for dummy stderr", (int)hnul ); + } + } + + DEBUG2 ("CreateProcess, path=`%s' args=`%s'", path, arg_string); + cr_flags |= CREATE_SUSPENDED; + if ( !CreateProcessA (path, + arg_string, + &sec_attr, /* process security attributes */ + &sec_attr, /* thread security attributes */ + TRUE, /* inherit handles */ + cr_flags, /* creation flags */ + envblock, /* environment */ + NULL, /* use current drive/directory */ + &si, /* startup information */ + &pi /* returns process information */ + ) ) { + DEBUG1 ("CreateProcess failed: ec=%d\n", (int) GetLastError ()); + free (arg_string); + return -1; + } + + /* Close the /dev/nul handle if used. */ + if (hnul != INVALID_HANDLE_VALUE ) { + if ( !CloseHandle ( hnul ) ) + DEBUG1 ("CloseHandle(hnul) failed: ec=%d\n", (int)GetLastError()); + } + + /* Close the other ends of the pipes. */ + for (i = 0; fd_parent_list[i].fd != -1; i++) + _gpgme_io_close (fd_parent_list[i].fd); + + DEBUG4 ("CreateProcess ready\n" + "- hProcess=%p hThread=%p\n" + "- dwProcessID=%d dwThreadId=%d\n", + pi.hProcess, pi.hThread, + (int) pi.dwProcessId, (int) pi.dwThreadId); + + if ( ResumeThread ( pi.hThread ) < 0 ) { + DEBUG1 ("ResumeThread failed: ec=%d\n", (int)GetLastError ()); + } + + if ( !CloseHandle (pi.hThread) ) { + DEBUG1 ("CloseHandle of thread failed: ec=%d\n", + (int)GetLastError ()); + } + + return handle_to_pid (pi.hProcess); +} + + +/* + * Select on the list of fds. + * Returns: -1 = error + * 0 = timeout or nothing to select + * >0 = number of signaled fds + */ +int +_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock ) +{ + HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; + int waitidx[MAXIMUM_WAIT_OBJECTS]; + int code, nwait; + int i, any; + int count; + void *dbg_help; + + restart: + DEBUG_BEGIN (dbg_help, 3, "select on [ "); + any = 0; + nwait = 0; + count = 0; + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + fds[i].signaled = 0; + if ( fds[i].for_read || fds[i].for_write ) { + if ( fds[i].frozen ) { + DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd ); + } + else if ( fds[i].for_read ) { + struct reader_context_s *c = find_reader (fds[i].fd,1); + + if (!c) { + DEBUG1 ("oops: no reader thread for fd %d", fds[i].fd); + } + else { + if ( nwait >= DIM (waitbuf) ) { + DEBUG_END (dbg_help, "oops ]"); + DEBUG0 ("Too many objects for WFMO!" ); + return -1; + } + waitidx[nwait] = i; + waitbuf[nwait++] = c->have_data_ev; + } + DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd ); + any = 1; + } + else if ( fds[i].for_write ) { + struct writer_context_s *c = find_writer (fds[i].fd,1); + + if (!c) { + DEBUG1 ("oops: no writer thread for fd %d", fds[i].fd); + } + else { + if ( nwait >= DIM (waitbuf) ) { + DEBUG_END (dbg_help, "oops ]"); + DEBUG0 ("Too many objects for WFMO!" ); + return -1; + } + waitidx[nwait] = i; + waitbuf[nwait++] = c->is_empty; + } + DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); + any = 1; + } + } + } + DEBUG_END (dbg_help, "]"); + if (!any) + return 0; + + code = WaitForMultipleObjects ( nwait, waitbuf, 0, nonblock ? 0 : 1000); + if ( code >= WAIT_OBJECT_0 && code < WAIT_OBJECT_0 + nwait ) { + /* This WFMO is a really silly function: It does return either + * the index of the signaled object or if 2 objects have been + * signalled at the same time, the index of the object with the + * lowest object is returned - so and how do we find out + * how many objects have been signaled???. + * The only solution I can imagine is to test each object starting + * with the returned index individually - how dull. + */ + any = 0; + for (i=code - WAIT_OBJECT_0; i < nwait; i++ ) { + if (WaitForSingleObject (waitbuf[i], 0) == WAIT_OBJECT_0) { + assert (waitidx[i] >=0 && waitidx[i] < nfds); + fds[waitidx[i]].signaled = 1; + any = 1; + count++; + } + } + if (!any) { + DEBUG0 ("Oops: No signaled objects found after WFMO"); + count = -1; + } + } + else if ( code == WAIT_TIMEOUT ) { + DEBUG0 ("WFMO timed out\n" ); + } + else if (code == WAIT_FAILED ) { + int le = (int)GetLastError (); + if ( le == ERROR_INVALID_HANDLE ) { + int k, j = handle_to_fd (waitbuf[i]); + + DEBUG1 ("WFMO invalid handle %d removed\n", j); + for (k=0 ; k < nfds; k++ ) { + if ( fds[k].fd == j ) { + fds[k].for_read = fds[k].for_write = 0; + goto restart; + } + } + DEBUG0 (" oops, or not???\n"); + } + DEBUG1 ("WFMO failed: %d\n", le ); + count = -1; + } + else { + DEBUG1 ("WFMO returned %d\n", code ); + count = -1; + } + + if ( count ) { + DEBUG_BEGIN (dbg_help, 3, " signaled [ "); + for ( i=0; i < nfds; i++ ) { + if ( fds[i].fd == -1 ) + continue; + if ( (fds[i].for_read || fds[i].for_write) && fds[i].signaled ) { + DEBUG_ADD2 (dbg_help, "%c%d ", + fds[i].for_read? 'r':'w',fds[i].fd ); + } + } + DEBUG_END (dbg_help, "]"); + } + + return count; +} + +void +_gpgme_io_subsystem_init (void) +{ + +} + + +/* Write the printable version of FD to the buffer BUF of length + BUFLEN. The printable version is the representation on the command + line that the child process expects. */ +int +_gpgme_io_fd2str (char *buf, int buflen, int fd) +{ + return snprintf (buf, buflen, "%d", fd); +} + + +/* The following interface is only useful for GPGME Glib. */ + +/* Look up the giochannel for file descriptor FD. */ +void * +gpgme_get_giochannel (int fd) +{ + return NULL; +} + diff --git a/libkdenetwork/libgpgme-copy/gpgme/w32-sema.c b/libkdenetwork/libgpgme-copy/gpgme/w32-sema.c new file mode 100644 index 000000000..c20f1a7b7 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/w32-sema.c @@ -0,0 +1,115 @@ +/* w32-sema.c + Copyright (C) 2001 Werner Koch (dd9jn) + Copyright (C) 2001, 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. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <windows.h> +#include <io.h> + +#include "util.h" +#include "sema.h" +#include "debug.h" + +static void +sema_fatal (const char *text) +{ + fprintf (stderr, "sema.c: %s\n", text); + abort (); +} + + +static void +critsect_init (struct critsect_s *s) +{ + CRITICAL_SECTION *mp; + static CRITICAL_SECTION init_lock; + static int initialized; + + if (!initialized) { + /* The very first time we call this function, we assume that + only one thread is running, so that we can bootstrap the + semaphore code. */ + InitializeCriticalSection (&init_lock); + initialized = 1; + } + if (!s) + return; /* we just want to initialize ourself */ + + /* first test whether it is really not initialized */ + EnterCriticalSection (&init_lock); + if ( s->private ) { + LeaveCriticalSection (&init_lock); + return; + } + /* now init it */ + mp = malloc ( sizeof *mp ); + if (!mp) { + LeaveCriticalSection (&init_lock); + sema_fatal ("out of core while creating critical section lock"); + } + InitializeCriticalSection (mp); + s->private = mp; + LeaveCriticalSection (&init_lock); +} + +void +_gpgme_sema_subsystem_init () +{ + /* fixme: we should check that there is only one thread running */ + critsect_init (NULL); +} + + +void +_gpgme_sema_cs_enter ( struct critsect_s *s ) +{ + if (!s->private) + critsect_init (s); + EnterCriticalSection ( (CRITICAL_SECTION*)s->private ); +} + +void +_gpgme_sema_cs_leave (struct critsect_s *s) +{ + if (!s->private) + critsect_init (s); + LeaveCriticalSection ((CRITICAL_SECTION*)s->private); +} + +void +_gpgme_sema_cs_destroy ( struct critsect_s *s ) +{ + if (s && s->private) { + DeleteCriticalSection ((CRITICAL_SECTION*)s->private); + free (s->private); + s->private = NULL; + } +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/w32-util.c b/libkdenetwork/libgpgme-copy/gpgme/w32-util.c new file mode 100644 index 000000000..889a6ec1a --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/w32-util.c @@ -0,0 +1,317 @@ +/* w32-util.c - Utility functions for the W32 API + Copyright (C) 1999 Free Software Foundation, Inc + Copyright (C) 2001 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <signal.h> +#include <fcntl.h> +#include <windows.h> +#include <shlobj.h> +#include <io.h> + +#include "util.h" +#include "sema.h" +#include "debug.h" + +DEFINE_STATIC_LOCK (get_path_lock); + + +#define RTLD_LAZY 0 + +static __inline__ void * +dlopen (const char * name, int flag) +{ + void * hd = LoadLibrary (name); + return hd; +} + +static __inline__ void * +dlsym (void * hd, const char * sym) +{ + if (hd && sym) + { + void * fnc = GetProcAddress (hd, sym); + if (!fnc) + return NULL; + return fnc; + } + return NULL; +} + +static __inline__ int +dlclose (void * hd) +{ + if (hd) + { + FreeLibrary (hd); + return 0; + } + return -1; +} + + +/* Return a string from the W32 Registry or NULL in case of error. + Caller must release the return value. A NULL for root is an alias + for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */ +static char * +read_w32_registry_string (const char *root, const char *dir, const char *name) +{ + HKEY root_key, key_handle; + DWORD n1, nbytes, type; + char *result = NULL; + + if ( !root ) + root_key = HKEY_CURRENT_USER; + else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) + root_key = HKEY_CLASSES_ROOT; + else if ( !strcmp( root, "HKEY_CURRENT_USER" ) ) + root_key = HKEY_CURRENT_USER; + else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) + root_key = HKEY_LOCAL_MACHINE; + else if ( !strcmp( root, "HKEY_USERS" ) ) + root_key = HKEY_USERS; + else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) + root_key = HKEY_PERFORMANCE_DATA; + else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) + root_key = HKEY_CURRENT_CONFIG; + else + return NULL; + + if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) ) + { + if (root) + return NULL; /* no need for a RegClose, so return direct */ + /* It seems to be common practise to fall back to HKLM. */ + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) + return NULL; /* still no need for a RegClose, so return direct */ + } + + nbytes = 1; + if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) + { + if (root) + goto leave; + /* Try to fallback to HKLM also vor a missing value. */ + RegCloseKey (key_handle); + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) + return NULL; /* Nope. */ + if (RegQueryValueEx ( key_handle, name, 0, NULL, NULL, &nbytes)) + goto leave; + } + result = malloc ( (n1=nbytes+1) ); + if ( !result ) + goto leave; + if ( RegQueryValueEx ( key_handle, name, 0, &type, result, &n1 ) ) + { + free(result); result = NULL; + goto leave; + } + result[nbytes] = 0; /* Make sure it is really a string. */ + if (type == REG_EXPAND_SZ && strchr (result, '%')) + { + char *tmp; + + n1 += 1000; + tmp = malloc (n1+1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) + { + free (tmp); + n1 = nbytes; + tmp = malloc (n1 + 1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) { + free (tmp); /* Oops - truncated, better don't expand at all. */ + goto leave; + } + tmp[nbytes] = 0; + free (result); + result = tmp; + } + else if (nbytes) /* Okay, reduce the length. */ + { + tmp[nbytes] = 0; + free (result); + result = malloc (strlen (tmp)+1); + if (!result) + result = tmp; + else + { + strcpy (result, tmp); + free (tmp); + } + } + else /* Error - don't expand. */ + { + free (tmp); + } + } + + leave: + RegCloseKey( key_handle ); + return result; +} + + +/* This is a helper function to load and run a Windows function from + either of one DLLs. */ +static HRESULT +w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e) +{ + static int initialized; + static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR); + + if (!initialized) + { + static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL }; + void *handle; + int i; + + initialized = 1; + + for (i=0, handle = NULL; !handle && dllnames[i]; i++) + { + handle = dlopen (dllnames[i], RTLD_LAZY); + if (handle) + { + func = dlsym (handle, "SHGetFolderPathA"); + if (!func) + { + dlclose (handle); + handle = NULL; + } + } + } + } + + if (func) + return func (a,b,c,d,e); + else + return -1; +} + + +static char * +find_program_in_registry (const char *name) +{ + char *program = NULL; + + program = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG", name); + if (program) + { + int i; + + DEBUG2 ("found %s in registry: `%s'", name, program); + for (i = 0; program[i]; i++) + { + if (program[i] == '/') + program[i] = '\\'; + } + } + return program; +} + + +static char * +find_program_at_standard_place (const char *name) +{ + char path[MAX_PATH]; + char *result = NULL; + + if (w32_shgetfolderpath (NULL, CSIDL_PROGRAM_FILES, NULL, 0, path) >= 0) + { + result = malloc (strlen (path) + 1 + strlen (name) + 1); + if (result) + { + strcpy (stpcpy (stpcpy (result, path), "\\"), name); + if (access (result, F_OK)) + { + free (result); + result = NULL; + } + } + } + return result; +} + +const char * +_gpgme_get_gpg_path (void) +{ + static char *gpg_program; + + LOCK (get_path_lock); + if (!gpg_program) + gpg_program = find_program_in_registry ("gpgProgram"); + if (!gpg_program) + gpg_program = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe"); +#ifdef GPG_PATH + if (!gpg_program) + gpg_program = GPG_PATH; +#endif + UNLOCK (get_path_lock); + return gpg_program; +} + +const char * +_gpgme_get_gpgsm_path (void) +{ + static char *gpgsm_program; + + LOCK (get_path_lock); + if (!gpgsm_program) + gpgsm_program = find_program_in_registry ("gpgsmProgram"); + if (!gpgsm_program) + gpgsm_program = find_program_at_standard_place ("GNU\\GnuPG\\gpgsm.exe"); +#ifdef GPGSM_PATH + if (!gpgsm_program) + gpgsm_program = GPGSM_PATH; +#endif + UNLOCK (get_path_lock); + return gpgsm_program; +} + + +/* Return an integer value from gpgme specific configuration + entries. VALUE receives that value; function returns true if a value + has been configured and false if not. */ +int +_gpgme_get_conf_int (const char *key, int *value) +{ + char *tmp = read_w32_registry_string (NULL, "Software\\GNU\\gpgme", key); + if (!tmp) + return 0; + *value = atoi (tmp); + free (tmp); + return 1; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/wait-global.c b/libkdenetwork/libgpgme-copy/gpgme/wait-global.c new file mode 100644 index 000000000..3b1e3d9af --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/wait-global.c @@ -0,0 +1,384 @@ +/* wait-global.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <errno.h> + +#include "gpgme.h" +#include "sema.h" +#include "util.h" +#include "context.h" +#include "wait.h" +#include "priv-io.h" + +/* The global event loop is used for all asynchronous operations + (except key listing) for which no user I/O callbacks are specified. + + A context sets up its initial I/O callbacks and then sends the + GPGME_EVENT_START event. After that, it is added to the global + list of active contexts. + + The gpgme_wait function contains a select() loop over all file + descriptors in all active contexts. If an error occurs, it closes + all fds in that context and moves the context to the global done + list. Likewise, if a context has removed all I/O callbacks, it is + moved to the global done list. + + All contexts in the global done list are eligible for being + returned by gpgme_wait if requested by the caller. */ + +/* The ctx_list_lock protects the list of active and done contexts. + Insertion into any of these lists is only allowed when the lock is + held. This allows a muli-threaded program to loop over gpgme_wait + and in parallel start asynchronous gpgme operations. + + However, the fd tables in the contexts are not protected by this + lock. They are only allowed to change either before the context is + added to the active list (ie, before the start event is signalled) + or in a callback handler. */ +DEFINE_STATIC_LOCK (ctx_list_lock); + +/* A ctx_list_item is an item in the global list of active or done + contexts. */ +struct ctx_list_item +{ + /* Every ctx_list_item is an element in a doubly linked list. The + list pointers are protected by the ctx_list_lock. */ + struct ctx_list_item *next; + struct ctx_list_item *prev; + + gpgme_ctx_t ctx; + /* The status is set when the ctx is moved to the done list. */ + gpgme_error_t status; +}; + +/* The active list contains all contexts that are in the global event + loop, have active I/O callbacks, and have already seen the start + event. */ +static struct ctx_list_item *ctx_active_list; + +/* The done list contains all contexts that have previously been + active but now are not active any longer, either because they + finished successfully or an I/O callback returned an error. The + status field in the list item contains the error value (or 0 if + successful). */ +static struct ctx_list_item *ctx_done_list; + + +/* Enter the context CTX into the active list. */ +static gpgme_error_t +ctx_active (gpgme_ctx_t ctx) +{ + struct ctx_list_item *li = malloc (sizeof (struct ctx_list_item)); + if (!li) + return gpg_error_from_errno (errno); + li->ctx = ctx; + + LOCK (ctx_list_lock); + /* Add LI to active list. */ + li->next = ctx_active_list; + li->prev = NULL; + if (ctx_active_list) + ctx_active_list->prev = li; + ctx_active_list = li; + UNLOCK (ctx_list_lock); + return 0; +} + + +/* Enter the context CTX into the done list with status STATUS. */ +static void +ctx_done (gpgme_ctx_t ctx, gpgme_error_t status) +{ + struct ctx_list_item *li; + + LOCK (ctx_list_lock); + li = ctx_active_list; + while (li && li->ctx != ctx) + li = li->next; + assert (li); + + /* Remove LI from active list. */ + if (li->next) + li->next->prev = li->prev; + if (li->prev) + li->prev->next = li->next; + else + ctx_active_list = li->next; + + li->status = status; + + /* Add LI to done list. */ + li->next = ctx_done_list; + li->prev = NULL; + if (ctx_done_list) + ctx_done_list->prev = li; + ctx_done_list = li; + UNLOCK (ctx_list_lock); +} + + +/* Find finished context CTX (or any context if CTX is NULL) and + return its status in STATUS after removing it from the done list. + If a matching context could be found, return it. Return NULL if no + context could be found. */ +static gpgme_ctx_t +ctx_wait (gpgme_ctx_t ctx, gpgme_error_t *status) +{ + struct ctx_list_item *li; + + LOCK (ctx_list_lock); + li = ctx_done_list; + if (ctx) + { + /* A specific context is requested. */ + while (li && li->ctx != ctx) + li = li->next; + } + if (li) + { + ctx = li->ctx; + if (status) + *status = li->status; + + /* Remove LI from done list. */ + if (li->next) + li->next->prev = li->prev; + if (li->prev) + li->prev->next = li->next; + else + ctx_done_list = li->next; + free (li); + } + else + ctx = NULL; + UNLOCK (ctx_list_lock); + return ctx; +} + + +/* Internal I/O callback functions. */ + +/* The add_io_cb and remove_io_cb handlers are shared with the private + event loops. */ + +void +_gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type, + void *type_data) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) data; + + assert (ctx); + + switch (type) + { + case GPGME_EVENT_START: + { + gpgme_error_t err = ctx_active (ctx); + + if (err) + { + /* An error occured. Close all fds in this context, and + send the error in a done event. */ + unsigned int idx; + + for (idx = 0; idx <= ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + } + break; + + case GPGME_EVENT_DONE: + { + gpgme_error_t *errp = (gpgme_error_t *) type_data; + assert (errp); + ctx_done (ctx, *errp); + } + break; + + case GPGME_EVENT_NEXT_KEY: + assert (!"Unexpected event GPGME_EVENT_NEXT_KEY"); + break; + + case GPGME_EVENT_NEXT_TRUSTITEM: + assert (!"Unexpected event GPGME_EVENT_NEXT_TRUSTITEM"); + break; + + default: + assert (!"Unexpected event"); + break; + } +} + + + +/* Perform asynchronous operations in the global event loop (ie, any + asynchronous operation except key listing and trustitem listing + operations). If CTX is not a null pointer, the function will + return if the asynchronous operation in the context CTX finished. + Otherwise the function will return if any asynchronous operation + finished. If HANG is zero, the function will not block for a long + time. Otherwise the function does not return until an operation + matching CTX finished. + + If a matching context finished, it is returned, and *STATUS is set + to the error value of the operation in that context. Otherwise, if + the timeout expires, NULL is returned and *STATUS is 0. If an + error occurs, NULL is returned and *STATUS is set to the error + value. */ +gpgme_ctx_t +gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang) +{ + do + { + unsigned int i = 0; + struct ctx_list_item *li; + struct fd_table fdt; + int nr; + + /* Collect the active file descriptors. */ + LOCK (ctx_list_lock); + for (li = ctx_active_list; li; li = li->next) + i += li->ctx->fdt.size; + fdt.fds = malloc (i * sizeof (struct io_select_fd_s)); + if (!fdt.fds) + { + int saved_errno = errno; + UNLOCK (ctx_list_lock); + if (status) + *status = gpg_error_from_errno (saved_errno); + return NULL; + } + fdt.size = i; + i = 0; + for (li = ctx_active_list; li; li = li->next) + { + memcpy (&fdt.fds[i], li->ctx->fdt.fds, + li->ctx->fdt.size * sizeof (struct io_select_fd_s)); + i += li->ctx->fdt.size; + } + UNLOCK (ctx_list_lock); + + nr = _gpgme_io_select (fdt.fds, fdt.size, 0); + if (nr < 0) + { + int saved_errno = errno; + free (fdt.fds); + if (status) + *status = gpg_error_from_errno (saved_errno); + return NULL; + } + + for (i = 0; i < fdt.size && nr; i++) + { + if (fdt.fds[i].fd != -1 && fdt.fds[i].signaled) + { + gpgme_ctx_t ictx; + gpgme_error_t err; + struct wait_item_s *item; + + assert (nr); + nr--; + + item = (struct wait_item_s *) fdt.fds[i].opaque; + assert (item); + ictx = item->ctx; + assert (ictx); + + err = _gpgme_run_io_cb (&fdt.fds[i], 0); + if (err) + { + /* An error occured. Close all fds in this context, + and signal it. */ + unsigned int idx; + + for (idx = 0; idx < ictx->fdt.size; idx++) + if (ictx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ictx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ictx->engine, GPGME_EVENT_DONE, + &err); + + /* Break out of the loop, and retry the select() + from scratch, because now all fds should be + gone. */ + break; + } + } + } + free (fdt.fds); + + /* Now some contexts might have finished successfully. */ + LOCK (ctx_list_lock); + retry: + for (li = ctx_active_list; li; li = li->next) + { + gpgme_ctx_t actx = li->ctx; + + for (i = 0; i < actx->fdt.size; i++) + if (actx->fdt.fds[i].fd != -1) + break; + if (i == actx->fdt.size) + { + gpgme_error_t err = 0; + + /* FIXME: This does not perform too well. We have to + release the lock because the I/O event handler + acquires it to remove the context from the active + list. Two alternative strategies are worth + considering: Either implement the DONE event handler + here in a lock-free manner, or save a list of all + contexts to be released and call the DONE events + afterwards. */ + UNLOCK (ctx_list_lock); + _gpgme_engine_io_event (actx->engine, GPGME_EVENT_DONE, &err); + LOCK (ctx_list_lock); + goto retry; + } + } + UNLOCK (ctx_list_lock); + + { + gpgme_ctx_t dctx = ctx_wait (ctx, status); + + if (dctx) + { + ctx = dctx; + hang = 0; + } + else if (!hang) + { + ctx = NULL; + if (status) + *status = 0; + } + } + } + while (hang); + + return ctx; +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/wait-private.c b/libkdenetwork/libgpgme-copy/gpgme/wait-private.c new file mode 100644 index 000000000..73f11b760 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/wait-private.c @@ -0,0 +1,147 @@ +/* wait-private.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <assert.h> +#include <errno.h> + +#include "gpgme.h" +#include "context.h" +#include "wait.h" +#include "ops.h" +#include "priv-io.h" +#include "util.h" + + +/* The private event loops are used for all blocking operations, and + for the key and trust item listing operations. They are completely + separated from each other. */ + + +/* Internal I/O callback functions. */ + +/* The add_io_cb and remove_io_cb handlers are shared with the global + event loops. */ + +void +_gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type, + void *type_data) +{ + switch (type) + { + case GPGME_EVENT_START: + /* Nothing to do here, as the wait routine is called after the + initialization is finished. */ + break; + + case GPGME_EVENT_DONE: + break; + + case GPGME_EVENT_NEXT_KEY: + _gpgme_op_keylist_event_cb (data, type, type_data); + break; + + case GPGME_EVENT_NEXT_TRUSTITEM: + _gpgme_op_trustlist_event_cb (data, type, type_data); + break; + } +} + + +/* If COND is a null pointer, wait until the blocking operation in CTX + finished and return its error value. Otherwise, wait until COND is + satisfied or the operation finished. */ +gpgme_error_t +_gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond) +{ + gpgme_error_t err = 0; + int hang = 1; + + do + { + int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0); + unsigned int i; + + if (nr < 0) + { + /* An error occured. Close all fds in this context, and + signal it. */ + unsigned int idx; + + err = gpg_error_from_errno (errno); + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + + return err; + } + + for (i = 0; i < ctx->fdt.size && nr; i++) + { + if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled) + { + ctx->fdt.fds[i].signaled = 0; + assert (nr); + nr--; + + err = _gpgme_run_io_cb (&ctx->fdt.fds[i], 0); + if (err) + { + /* An error occured. Close all fds in this context, + and signal it. */ + unsigned int idx; + + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + return err; + } + } + } + + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + { + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + hang = 0; + } + if (cond && *cond) + hang = 0; + } + while (hang); + + return 0; +} + + +/* Wait until the blocking operation in context CTX has finished and + return the error value. */ +gpgme_error_t +_gpgme_wait_one (gpgme_ctx_t ctx) +{ + return _gpgme_wait_on_condition (ctx, NULL); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/wait-user.c b/libkdenetwork/libgpgme-copy/gpgme/wait-user.c new file mode 100644 index 000000000..605401e93 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/wait-user.c @@ -0,0 +1,122 @@ +/* wait-user.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <assert.h> + +#include "gpgme.h" +#include "context.h" +#include "priv-io.h" +#include "wait.h" + + +/* The user event loops are used for all asynchronous operations for + which a user callback is defined. */ + + +/* Internal I/O Callbacks. */ + +gpgme_error_t +_gpgme_user_io_cb_handler (void *data, int fd) +{ + gpgme_error_t err; + struct tag *tag = (struct tag *) data; + gpgme_ctx_t ctx; + + assert (data); + ctx = tag->ctx; + assert (ctx); + + err = _gpgme_run_io_cb (&ctx->fdt.fds[tag->idx], 0); + if (err) + { + unsigned int idx; + + for (idx = 0; idx < ctx->fdt.size; idx++) + if (ctx->fdt.fds[idx].fd != -1) + _gpgme_io_close (ctx->fdt.fds[idx].fd); + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + else + { + unsigned int i; + + for (i = 0; i < ctx->fdt.size; i++) + if (ctx->fdt.fds[i].fd != -1) + break; + if (i == ctx->fdt.size) + _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err); + } + return 0; +} + + +/* Register the file descriptor FD with the handler FNC (which gets + FNC_DATA as its first argument) for the direction DIR. DATA should + be the context for which the fd is added. R_TAG will hold the tag + that can be used to remove the fd. */ +gpgme_error_t +_gpgme_wait_user_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc, + void *fnc_data, void **r_tag) +{ + gpgme_ctx_t ctx = (gpgme_ctx_t) data; + struct tag *tag; + gpgme_error_t err; + + assert (ctx); + err = _gpgme_add_io_cb (data, fd, dir, fnc, fnc_data, r_tag); + if (err) + return err; + tag = *r_tag; + assert (tag); + err = (*ctx->io_cbs.add) (ctx->io_cbs.add_priv, fd, dir, + _gpgme_user_io_cb_handler, *r_tag, + &tag->user_tag); + if (err) + _gpgme_remove_io_cb (*r_tag); + return err; +} + + +void +_gpgme_wait_user_remove_io_cb (void *data) +{ + struct tag *tag = (struct tag *) data; + gpgme_ctx_t ctx; + + assert (tag); + ctx = tag->ctx; + + (*ctx->io_cbs.remove) (tag->user_tag); + _gpgme_remove_io_cb (data); +} + + +void +_gpgme_wait_user_event_cb (void *data, gpgme_event_io_t type, void *type_data) +{ + gpgme_ctx_t ctx = data; + + if (ctx->io_cbs.event) + (*ctx->io_cbs.event) (ctx->io_cbs.event_priv, type, type_data); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/wait.c b/libkdenetwork/libgpgme-copy/gpgme/wait.c new file mode 100644 index 000000000..16a9f2308 --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/wait.c @@ -0,0 +1,204 @@ +/* wait.c + Copyright (C) 2000 Werner Koch (dd9jn) + Copyright (C) 2001, 2002, 2003, 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. */ + +#if HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <sys/types.h> + +#include "util.h" +#include "context.h" +#include "ops.h" +#include "wait.h" +#include "sema.h" +#include "priv-io.h" +#include "engine.h" +#include "debug.h" + + +void +_gpgme_fd_table_init (fd_table_t fdt) +{ + fdt->fds = NULL; + fdt->size = 0; +} + +void +_gpgme_fd_table_deinit (fd_table_t fdt) +{ + if (fdt->fds) + free (fdt->fds); +} + + +/* XXX We should keep a marker and roll over for speed. */ +static gpgme_error_t +fd_table_put (fd_table_t fdt, int fd, int dir, void *opaque, int *idx) +{ + unsigned int i, j; + struct io_select_fd_s *new_fds; + + for (i = 0; i < fdt->size; i++) + { + if (fdt->fds[i].fd == -1) + break; + } + if (i == fdt->size) + { +#define FDT_ALLOCSIZE 10 + new_fds = realloc (fdt->fds, (fdt->size + FDT_ALLOCSIZE) + * sizeof (*new_fds)); + if (!new_fds) + return gpg_error_from_errno (errno); + + fdt->fds = new_fds; + fdt->size += FDT_ALLOCSIZE; + for (j = 0; j < FDT_ALLOCSIZE; j++) + fdt->fds[i + j].fd = -1; + } + + fdt->fds[i].fd = fd; + fdt->fds[i].for_read = (dir == 1); + fdt->fds[i].for_write = (dir == 0); + fdt->fds[i].frozen = 0; + fdt->fds[i].signaled = 0; + fdt->fds[i].opaque = opaque; + *idx = i; + return 0; +} + + +/* Register the file descriptor FD with the handler FNC (which gets + FNC_DATA as its first argument) for the direction DIR. DATA should + be the context for which the fd is added. R_TAG will hold the tag + that can be used to remove the fd. */ +gpgme_error_t +_gpgme_add_io_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc, + void *fnc_data, void **r_tag) +{ + gpgme_error_t err; + gpgme_ctx_t ctx = (gpgme_ctx_t) data; + fd_table_t fdt; + struct wait_item_s *item; + struct tag *tag; + + assert (fnc); + assert (ctx); + + fdt = &ctx->fdt; + assert (fdt); + + tag = malloc (sizeof *tag); + if (!tag) + return gpg_error_from_errno (errno); + tag->ctx = ctx; + + /* Allocate a structure to hold information about the handler. */ + item = calloc (1, sizeof *item); + if (!item) + { + int saved_errno = errno; + free (tag); + return gpg_error_from_errno (saved_errno); + } + item->ctx = ctx; + item->dir = dir; + item->handler = fnc; + item->handler_value = fnc_data; + + err = fd_table_put (fdt, fd, dir, item, &tag->idx); + if (err) + { + free (tag); + free (item); + return err; + } + + *r_tag = tag; + return 0; +} + + +void +_gpgme_remove_io_cb (void *data) +{ + struct tag *tag = data; + gpgme_ctx_t ctx; + fd_table_t fdt; + int idx; + + assert (tag); + ctx = tag->ctx; + assert (ctx); + fdt = &ctx->fdt; + assert (fdt); + idx = tag->idx; + + DEBUG2 ("setting fd %d (item=%p) done", fdt->fds[idx].fd, + fdt->fds[idx].opaque); + free (fdt->fds[idx].opaque); + free (tag); + + /* Free the table entry. */ + fdt->fds[idx].fd = -1; + fdt->fds[idx].for_read = 0; + fdt->fds[idx].for_write = 0; + fdt->fds[idx].opaque = NULL; +} + + +/* This is slightly embarrassing. The problem is that running an I/O + callback _may_ influence the status of other file descriptors. Our + own event loops could compensate for that, but the external event + loops cannot. FIXME: We may still want to optimize this a bit when + we are called from our own event loops. So if CHECKED is 1, the + check is skipped. */ +gpgme_error_t +_gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked) +{ + struct wait_item_s *item; + item = (struct wait_item_s *) an_fds->opaque; + assert (item); + + if (!checked) + { + int nr; + struct io_select_fd_s fds; + + fds = *an_fds; + fds.signaled = 0; + /* Just give it a quick poll. */ + nr = _gpgme_io_select (&fds, 1, 1); + assert (nr <= 1); + if (nr < 0) + return errno; + else if (nr == 0) + /* The status changed in the meantime, there is nothing left + to do. */ + return 0; + } + + return item->handler (item->handler_value, an_fds->fd); +} diff --git a/libkdenetwork/libgpgme-copy/gpgme/wait.h b/libkdenetwork/libgpgme-copy/gpgme/wait.h new file mode 100644 index 000000000..eafbb6f6d --- /dev/null +++ b/libkdenetwork/libgpgme-copy/gpgme/wait.h @@ -0,0 +1,82 @@ +/* wait.h - Definitions for the wait queue interface. + 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. */ + +#ifndef WAIT_H +#define WAIT_H + +#include "gpgme.h" +#include "sema.h" + +struct fd_table +{ + struct io_select_fd_s *fds; + size_t size; +}; +typedef struct fd_table *fd_table_t; + +/* Wait items are hooked into the io_select_fd_s to connect an fd with + a callback handler. */ +struct wait_item_s +{ + gpgme_ctx_t ctx; + gpgme_io_cb_t handler; + void *handler_value; + int dir; +}; + +/* A registered fd handler is removed later using the tag that + identifies it. */ +struct tag +{ + /* The context for which the fd was registered. */ + gpgme_ctx_t ctx; + + /* The index into the fd table for this context. */ + int idx; + + /* This is used by the wrappers for the user event loop. */ + void *user_tag; +}; + + +void _gpgme_fd_table_init (fd_table_t fdt); +void _gpgme_fd_table_deinit (fd_table_t fdt); + +gpgme_error_t _gpgme_add_io_cb (void *data, int fd, int dir, + gpgme_io_cb_t fnc, void *fnc_data, void **r_tag); +void _gpgme_remove_io_cb (void *tag); +void _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type, + void *type_data); +void _gpgme_wait_global_event_cb (void *data, gpgme_event_io_t type, + void *type_data); + +gpgme_error_t _gpgme_wait_user_add_io_cb (void *data, int fd, int dir, + gpgme_io_cb_t fnc, void *fnc_data, + void **r_tag); +void _gpgme_wait_user_remove_io_cb (void *tag); +void _gpgme_wait_user_event_cb (void *data, gpgme_event_io_t type, + void *type_data); + +gpgme_error_t _gpgme_wait_one (gpgme_ctx_t ctx); + +gpgme_error_t _gpgme_run_io_cb (struct io_select_fd_s *an_fds, int checked); + +#endif /* WAIT_H */ |