From f12433c1e476f52c92496a885c1ffcd10fa2a322 Mon Sep 17 00:00:00 2001 From: Marcus Brinkmann Date: Sun, 28 Jul 2002 18:41:02 +0000 Subject: [PATCH] 2002-07-28 Marcus Brinkmann * 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. --- gpgme/ChangeLog | 87 +++++++++++++ gpgme/Makefile.am | 9 +- gpgme/context.h | 1 + gpgme/data.c | 5 + gpgme/decrypt-verify.c | 2 +- gpgme/decrypt.c | 8 +- gpgme/delete.c | 6 +- gpgme/edit.c | 158 ++++++++++++++++++++++ gpgme/encrypt-sign.c | 6 +- gpgme/encrypt.c | 10 +- gpgme/engine-gpgsm.c | 12 +- gpgme/engine.c | 25 +++- gpgme/engine.h | 5 +- gpgme/export.c | 2 +- gpgme/genkey.c | 6 +- gpgme/gpgme.c | 1 + gpgme/gpgme.h | 95 ++++++++++++++ gpgme/import.c | 28 ++-- gpgme/io.h | 2 +- gpgme/keylist.c | 6 +- gpgme/mkstatus | 15 +-- gpgme/ops.h | 18 ++- gpgme/passphrase.c | 25 ++-- gpgme/posix-io.c | 4 +- gpgme/progress.c | 4 +- gpgme/rungpg.c | 289 +++++++++++++++++++++++++---------------- gpgme/rungpg.h | 101 ++------------ gpgme/sign.c | 6 +- gpgme/trustlist.c | 4 +- gpgme/types.h | 4 + gpgme/verify.c | 56 ++++---- gpgme/w32-io.c | 4 +- gpgme/wait.c | 2 +- 33 files changed, 686 insertions(+), 320 deletions(-) create mode 100644 gpgme/edit.c diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 11432d4..8259a37 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,90 @@ +2002-07-28 Marcus Brinkmann + + * 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 * delete.c (delete_problem): New case ambigious specification. diff --git a/gpgme/Makefile.am b/gpgme/Makefile.am index 6f196ba..4f28440 100644 --- a/gpgme/Makefile.am +++ b/gpgme/Makefile.am @@ -32,7 +32,9 @@ libgpgme_la_LDFLAGS = -version-info \ @LIBGPGME_LT_CURRENT@:@LIBGPGME_LT_REVISION@:@LIBGPGME_LT_AGE@ if BUILD_ASSUAN AM_CPPFLAGS = -I$(top_srcdir)/assuan -libgpgme_la_LIBADD = ../assuan/libassuan.la ../jnlib/libjnlib.la +assuan_libobjs = ../assuan/libassuan.la ../jnlib/libjnlib.la @LIBOBJS@ +else +assuan_libobjs = endif if HAVE_PTHREAD @@ -75,6 +77,7 @@ libgpgme_la_SOURCES = \ export.c \ genkey.c \ delete.c \ + edit.c \ rungpg.c rungpg.h status-table.h \ engine-gpgsm.c engine-gpgsm.h \ engine.c engine.h \ @@ -82,11 +85,11 @@ libgpgme_la_SOURCES = \ ${system_components} \ debug.c debug.h \ gpgme.c version.c errors.c -libgpgme_la_LDADD = @LIBOBJS@ +libgpgme_la_LIBADD = ${assuan_libobjs} @LIBOBJS@ errors.c : gpgme.h $(srcdir)/mkerrors < $(srcdir)/gpgme.h > errors.c status-table.h : rungpg.h - $(srcdir)/mkstatus < $(srcdir)/rungpg.h > status-table.h + $(srcdir)/mkstatus < $(srcdir)/gpgme.h > status-table.h diff --git a/gpgme/context.h b/gpgme/context.h index 256c480..3e68cbf 100644 --- a/gpgme/context.h +++ b/gpgme/context.h @@ -83,6 +83,7 @@ struct gpgme_context_s DeleteResult delete; GenKeyResult genkey; KeylistResult keylist; + EditResult edit; } result; /* Last signature notation. */ diff --git a/gpgme/data.c b/gpgme/data.c index 35bf802..dcdf4ec 100644 --- a/gpgme/data.c +++ b/gpgme/data.c @@ -566,6 +566,11 @@ gpgme_data_read (GpgmeData dh, void *buffer, size_t length, size_t *nread) switch (dh->type) { + case GPGME_DATA_TYPE_NONE: + *nread = 0; + return mk_error(EOF); + break; + case GPGME_DATA_TYPE_MEM: nbytes = dh->len - dh->readpos; if (!nbytes) diff --git a/gpgme/decrypt-verify.c b/gpgme/decrypt-verify.c index e458b01..b78df70 100644 --- a/gpgme/decrypt-verify.c +++ b/gpgme/decrypt-verify.c @@ -31,7 +31,7 @@ static void -decrypt_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +decrypt_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { _gpgme_decrypt_status_handler (ctx, code, args); _gpgme_verify_status_handler (ctx, code, args); diff --git a/gpgme/decrypt.c b/gpgme/decrypt.c index 421ddbc..a94cc46 100644 --- a/gpgme/decrypt.c +++ b/gpgme/decrypt.c @@ -47,7 +47,7 @@ _gpgme_release_decrypt_result (DecryptResult result) void -_gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { _gpgme_passphrase_status_handler (ctx, code, args); @@ -57,18 +57,18 @@ _gpgme_decrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: if (ctx->result.decrypt->failed) ctx->error = mk_error (Decryption_Failed); else if (!ctx->result.decrypt->okay) ctx->error = mk_error (No_Data); break; - case STATUS_DECRYPTION_OKAY: + case GPGME_STATUS_DECRYPTION_OKAY: ctx->result.decrypt->okay = 1; break; - case STATUS_DECRYPTION_FAILED: + case GPGME_STATUS_DECRYPTION_FAILED: ctx->result.decrypt->failed = 1; break; diff --git a/gpgme/delete.c b/gpgme/delete.c index 94d28fe..6e9b6c1 100644 --- a/gpgme/delete.c +++ b/gpgme/delete.c @@ -56,7 +56,7 @@ _gpgme_release_delete_result (DeleteResult result) static void -delete_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +delete_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; @@ -64,7 +64,7 @@ delete_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: switch (ctx->result.delete->problem) { case DELETE_No_Problem: @@ -83,7 +83,7 @@ delete_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) } break; - case STATUS_DELETE_PROBLEM: + case GPGME_STATUS_DELETE_PROBLEM: ctx->result.delete->problem = atoi (args); break; diff --git a/gpgme/edit.c b/gpgme/edit.c new file mode 100644 index 0000000..9b9ee74 --- /dev/null +++ b/gpgme/edit.c @@ -0,0 +1,158 @@ +/* edit.c - key edit functions + * Copyright (C) 2002 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include + +#include "util.h" +#include "context.h" +#include "ops.h" + + +struct edit_result_s +{ + GpgmeEditCb fnc; + void *fnc_value; +}; + +void +_gpgme_release_edit_result (EditResult result) +{ + if (!result) + return; + xfree (result); +} + +void +_gpgme_edit_status_handler (GpgmeCtx ctx, GpgmeStatusCode status, char *args) +{ + _gpgme_passphrase_status_handler (ctx, status, args); + + if (ctx->error) + return; + + ctx->error = (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, args, NULL); +} + +static const char * +command_handler (void *opaque, GpgmeStatusCode status, const char *args) +{ + GpgmeCtx ctx = opaque; + const char *result; + + result = _gpgme_passphrase_command_handler (ctx, status, args); + + if (!result) + ctx->error = (*ctx->result.edit->fnc) (ctx->result.edit->fnc_value, status, args, &result); + + return result; +} + +static GpgmeError +_gpgme_op_edit_start (GpgmeCtx ctx, int synchronous, + GpgmeKey key, + GpgmeEditCb fnc, void *fnc_value, + GpgmeData out) +{ + GpgmeError err = 0; + + if (!fnc) + return mk_error (Invalid_Value); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + goto leave; + + assert (!ctx->result.edit); + ctx->result.edit = xtrymalloc (sizeof *ctx->result.edit); + if (!ctx->result.edit) + { + err = mk_error (Out_Of_Core); + goto leave; + } + ctx->result.edit->fnc = fnc; + ctx->result.edit->fnc_value = fnc_value; + + /* Check the supplied data. */ + if (!out || gpgme_data_get_type (out) != GPGME_DATA_TYPE_NONE) + { + err = mk_error (Invalid_Value); + goto leave; + } + _gpgme_data_set_mode (out, GPGME_DATA_MODE_IN); + + err = _gpgme_engine_set_command_handler (ctx->engine, command_handler, + ctx, out); + if (err) + goto leave; + + _gpgme_engine_set_status_handler (ctx->engine, _gpgme_edit_status_handler, + ctx); + + _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity); + + _gpgme_engine_op_edit (ctx->engine, key, out); + + /* And kick off the process. */ + err = _gpgme_engine_start (ctx->engine, ctx); + + leave: + if (err) + { + ctx->pending = 0; + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } + return err; +} + +GpgmeError +gpgme_op_edit_start (GpgmeCtx ctx, + GpgmeKey key, + GpgmeEditCb fnc, void *fnc_value, + GpgmeData out) +{ + return _gpgme_op_edit_start (ctx, 0, key, fnc, fnc_value, out); +} + +/** + * gpgme_op_edit: + * @ctx: The context + * @key: The key to be edited. + * @fnc: An edit callback handler. + * @fnc_value: To be passed to @fnc as first arg. + * @out: The output. + * + * Return value: 0 on success or an error code. + **/ +GpgmeError +gpgme_op_edit (GpgmeCtx ctx, + GpgmeKey key, + GpgmeEditCb fnc, void *fnc_value, + GpgmeData out) +{ + GpgmeError err = _gpgme_op_edit_start (ctx, 1, key, fnc, fnc_value, out); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} diff --git a/gpgme/encrypt-sign.c b/gpgme/encrypt-sign.c index 60673ec..3ea6f28 100644 --- a/gpgme/encrypt-sign.c +++ b/gpgme/encrypt-sign.c @@ -34,21 +34,21 @@ static void -encrypt_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +encrypt_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { char *encrypt_info = 0; size_t encrypt_info_len; _gpgme_encrypt_status_handler (ctx, code, args); - if (code == STATUS_EOF) + if (code == GPGME_STATUS_EOF) { encrypt_info = gpgme_data_release_and_get_mem (ctx->op_info, &encrypt_info_len); ctx->op_info = NULL; } _gpgme_sign_status_handler (ctx, code, args); - if (code == STATUS_EOF && encrypt_info) + if (code == GPGME_STATUS_EOF && encrypt_info) _gpgme_data_append (ctx->op_info, encrypt_info, encrypt_info_len); } diff --git a/gpgme/encrypt.c b/gpgme/encrypt.c index 52bd713..57ec978 100644 --- a/gpgme/encrypt.c +++ b/gpgme/encrypt.c @@ -100,7 +100,7 @@ append_xml_encinfo (GpgmeData *rdh, char *args) void -_gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; @@ -108,7 +108,7 @@ _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: if (ctx->result.encrypt->xmlinfo) { append_xml_encinfo (&ctx->result.encrypt->xmlinfo, NULL); @@ -121,12 +121,12 @@ _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) ctx->error = mk_error (Invalid_Recipients); break; - case STATUS_INV_RECP: + case GPGME_STATUS_INV_RECP: ctx->result.encrypt->invalid_recipients++; append_xml_encinfo (&ctx->result.encrypt->xmlinfo, args); break; - case STATUS_NO_RECP: + case GPGME_STATUS_NO_RECP: ctx->result.encrypt->no_valid_recipients = 1; break; @@ -137,7 +137,7 @@ _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) void -_gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_encrypt_sym_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { _gpgme_passphrase_status_handler (ctx, code, args); } diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 07692d4..1d7ef2e 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -545,7 +545,7 @@ _gpgme_gpgsm_release (GpgsmObject gpgsm) } /* Forward declaration. */ -static GpgStatusCode parse_status (const char *name); +static GpgmeStatusCode parse_status (const char *name); static GpgmeError gpgsm_assuan_simple_command (ASSUAN_CONTEXT ctx, char *cmd, GpgStatusHandler status_fnc, @@ -580,7 +580,7 @@ gpgsm_assuan_simple_command (ASSUAN_CONTEXT ctx, char *cmd, GpgStatusHandler sta && line[0] == 'S' && line[1] == ' ') { char *rest; - GpgStatusCode r; + GpgmeStatusCode r; rest = strchr (line + 2, ' '); if (!rest) @@ -772,7 +772,7 @@ gpgsm_set_recipients (GpgsmObject gpgsm, GpgmeRecipients recp) } xfree (line); if (!valid_recipients && gpgsm->status.fnc) - gpgsm->status.fnc (gpgsm->status.fnc_value, STATUS_NO_RECP, ""); + gpgsm->status.fnc (gpgsm->status.fnc_value, GPGME_STATUS_NO_RECP, ""); return 0; } @@ -1166,7 +1166,7 @@ status_cmp (const void *ap, const void *bp) } -static GpgStatusCode +static GpgmeStatusCode parse_status (const char *name) { struct status_table_s t, *r; @@ -1216,7 +1216,7 @@ gpgsm_status_handler (void *opaque, int fd) } if (gpgsm->status.fnc) - gpgsm->status.fnc (gpgsm->status.fnc_value, STATUS_EOF, ""); + gpgsm->status.fnc (gpgsm->status.fnc_value, GPGME_STATUS_EOF, ""); /* XXX: Try our best to terminate the connection. */ if (err) @@ -1296,7 +1296,7 @@ gpgsm_status_handler (void *opaque, int fd) && line[0] == 'S' && line[1] == ' ') { char *rest; - GpgStatusCode r; + GpgmeStatusCode r; rest = strchr (line + 2, ' '); if (!rest) diff --git a/gpgme/engine.c b/gpgme/engine.c index 52d00e1..b33bfe9 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -262,7 +262,8 @@ _gpgme_engine_set_status_handler (EngineObject engine, GpgmeError _gpgme_engine_set_command_handler (EngineObject engine, - GpgCommandHandler fnc, void *fnc_value) + GpgCommandHandler fnc, void *fnc_value, + GpgmeData linked_data) { if (!engine) return mk_error (Invalid_Value); @@ -270,7 +271,8 @@ _gpgme_engine_set_command_handler (EngineObject engine, switch (engine->protocol) { case GPGME_PROTOCOL_OpenPGP: - return _gpgme_gpg_set_command_handler (engine->engine.gpg, fnc, fnc_value); + return _gpgme_gpg_set_command_handler (engine->engine.gpg, + fnc, fnc_value, linked_data); case GPGME_PROTOCOL_CMS: /* FIXME */ break; @@ -340,6 +342,25 @@ _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret) } +GpgmeError +_gpgme_engine_op_edit (EngineObject engine, GpgmeKey key, GpgmeData out) +{ + if (!engine) + return mk_error (Invalid_Value); + + switch (engine->protocol) + { + case GPGME_PROTOCOL_OpenPGP: + return _gpgme_gpg_op_edit (engine->engine.gpg, key, out); + case GPGME_PROTOCOL_CMS: + /* FIXME */ + return mk_error (Not_Implemented); + default: + break; + } + return 0; +} + GpgmeError _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph, int use_armor) diff --git a/gpgme/engine.h b/gpgme/engine.h index 5f23d2f..acc3367 100644 --- a/gpgme/engine.h +++ b/gpgme/engine.h @@ -34,7 +34,8 @@ void _gpgme_engine_set_status_handler (EngineObject engine, GpgStatusHandler fnc, void *fnc_value); GpgmeError _gpgme_engine_set_command_handler (EngineObject engine, GpgCommandHandler fnc, - void *fnc_value); + void *fnc_value, + GpgmeData data); GpgmeError _gpgme_engine_set_colon_line_handler (EngineObject gpg, GpgColonLineHandler fnc, void *fnc_value); @@ -43,6 +44,8 @@ GpgmeError _gpgme_engine_op_decrypt (EngineObject engine, GpgmeData ciph, GpgmeData plain); GpgmeError _gpgme_engine_op_delete (EngineObject engine, GpgmeKey key, int allow_secret); +GpgmeError _gpgme_engine_op_edit (EngineObject engine, GpgmeKey key, + GpgmeData out); GpgmeError _gpgme_engine_op_encrypt (EngineObject engine, GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph, int use_armor); diff --git a/gpgme/export.c b/gpgme/export.c index 968de2e..341d260 100644 --- a/gpgme/export.c +++ b/gpgme/export.c @@ -31,7 +31,7 @@ static void -export_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +export_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; diff --git a/gpgme/genkey.c b/gpgme/genkey.c index 9f42cb7..41d0e1b 100644 --- a/gpgme/genkey.c +++ b/gpgme/genkey.c @@ -46,7 +46,7 @@ _gpgme_release_genkey_result (GenKeyResult result) } static void -genkey_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +genkey_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { _gpgme_progress_status_handler (ctx, code, args); @@ -56,7 +56,7 @@ genkey_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_KEY_CREATED: + case GPGME_STATUS_KEY_CREATED: if (args && *args) { if (*args == 'B' || *args == 'P') @@ -66,7 +66,7 @@ genkey_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) } break; - case STATUS_EOF: + case GPGME_STATUS_EOF: /* FIXME: Should return some more useful error value. */ if (!ctx->result.genkey->created_primary && !ctx->result.genkey->created_sub) diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 2caa737..f96bf5a 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -95,6 +95,7 @@ _gpgme_release_result (GpgmeCtx ctx) _gpgme_release_delete_result (ctx->result.delete); _gpgme_release_genkey_result (ctx->result.genkey); _gpgme_release_keylist_result (ctx->result.keylist); + _gpgme_release_edit_result (ctx->result.edit); memset (&ctx->result, 0, sizeof (ctx->result)); _gpgme_set_op_info (ctx, NULL); ctx->error = 0; diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 7f0a9bf..0073c92 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -222,6 +222,90 @@ typedef enum GpgmeProtocol; +/* The possible stati for the edit operation. */ + +typedef enum { + GPGME_STATUS_EOF, + /* mkstatus 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_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 , +} GpgmeStatusCode; + + /* The available keylist mode flags. */ #define GPGME_KEYLIST_MODE_LOCAL 1 #define GPGME_KEYLIST_MODE_EXTERN 2 @@ -237,6 +321,9 @@ typedef const char *(*GpgmePassphraseCb) (void *hook, const char *desc, typedef void (*GpgmeProgressCb) (void *opaque, const char *what, int type, int current, int total); +/* Interact with the user about an edit operation. */ +typedef GpgmeError (*GpgmeEditCb) (void *opaque, GpgmeStatusCode status, + const char *args, const char **reply); /* Context management functions. */ @@ -598,6 +685,14 @@ GpgmeError gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key, GpgmeError gpgme_op_delete (GpgmeCtx ctx, const GpgmeKey key, int allow_secret); +/* Edit the key KEY. Send status and command requests to FNC and + output of edit commands to OUT. */ +GpgmeError gpgme_op_edit_start (GpgmeCtx ctx, GpgmeKey key, + GpgmeEditCb fnc, void *fnc_value, + GpgmeData out); +GpgmeError gpgme_op_edit (GpgmeCtx ctx, GpgmeKey key, + GpgmeEditCb fnc, void *fnc_value, + GpgmeData out); /* Key management functions */ diff --git a/gpgme/import.c b/gpgme/import.c index 754bdb9..e157363 100644 --- a/gpgme/import.c +++ b/gpgme/import.c @@ -51,7 +51,7 @@ _gpgme_release_import_result (ImportResult result) the data buffer. With args of NULL the xml structure is closed. */ static void -append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args) +append_xml_impinfo (GpgmeData *rdh, GpgmeStatusCode code, char *args) { #define MAX_IMPORTED_FIELDS 14 static const char *const imported_fields[MAX_IMPORTED_FIELDS] @@ -68,14 +68,14 @@ append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args) int i; /* Verify that we can use the args. */ - if (code != STATUS_EOF) + if (code != GPGME_STATUS_EOF) { if (!args) return; - if (code == STATUS_IMPORTED) + if (code == GPGME_STATUS_IMPORTED) field_name = imported_fields; - else if (code == STATUS_IMPORT_RES) + else if (code == GPGME_STATUS_IMPORT_RES) field_name = import_res_fields; else return; @@ -94,7 +94,7 @@ append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args) /* gpgsm does not print a useful user ID and uses a fingerprint instead of the key ID. */ - if (code == STATUS_IMPORTED && field[0] && strlen (field[0]) > 16) + if (code == GPGME_STATUS_IMPORTED && field[0] && strlen (field[0]) > 16) field_name = imported_fields_x509; } @@ -109,16 +109,16 @@ append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args) else dh = *rdh; - if (code == STATUS_EOF) + if (code == GPGME_STATUS_EOF) { /* Just close the XML containter. */ _gpgme_data_append_string (dh, "\n"); } else { - if (code == STATUS_IMPORTED) + if (code == GPGME_STATUS_IMPORTED) _gpgme_data_append_string (dh, " \n"); - else if (code == STATUS_IMPORT_RES) + else if (code == GPGME_STATUS_IMPORT_RES) _gpgme_data_append_string (dh, " \n"); for (i = 0; field_name[i]; i++) @@ -132,16 +132,16 @@ append_xml_impinfo (GpgmeData *rdh, GpgStatusCode code, char *args) _gpgme_data_append_string (dh, ">\n"); } - if (code == STATUS_IMPORTED) + if (code == GPGME_STATUS_IMPORTED) _gpgme_data_append_string (dh, " \n"); - else if (code == STATUS_IMPORT_RES) + else if (code == GPGME_STATUS_IMPORT_RES) _gpgme_data_append_string (dh, " \n"); } } static void -import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; @@ -149,7 +149,7 @@ import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: if (ctx->result.import->xmlinfo) { append_xml_impinfo (&ctx->result.import->xmlinfo, code, NULL); @@ -159,9 +159,9 @@ import_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) /* XXX Calculate error value. */ break; - case STATUS_IMPORTED: + case GPGME_STATUS_IMPORTED: ctx->result.import->any_imported = 1; - case STATUS_IMPORT_RES: + case GPGME_STATUS_IMPORT_RES: append_xml_impinfo (&ctx->result.import->xmlinfo, code, args); break; diff --git a/gpgme/io.h b/gpgme/io.h index ca3eba2..68d20fd 100644 --- a/gpgme/io.h +++ b/gpgme/io.h @@ -59,7 +59,7 @@ int _gpgme_io_spawn (const char *path, char **argv, 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 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock); #endif /* IO_H */ diff --git a/gpgme/keylist.c b/gpgme/keylist.c index baf1efc..27a04b8 100644 --- a/gpgme/keylist.c +++ b/gpgme/keylist.c @@ -88,7 +88,7 @@ append_xml_keylistinfo (GpgmeData *rdh, char *args) static void -keylist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; @@ -96,11 +96,11 @@ keylist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_TRUNCATED: + case GPGME_STATUS_TRUNCATED: ctx->result.keylist->truncated = 1; break; - case STATUS_EOF: + case GPGME_STATUS_EOF: finish_key (ctx); if (ctx->result.keylist->truncated) append_xml_keylistinfo (&ctx->result.keylist->xmlinfo, "1"); diff --git a/gpgme/mkstatus b/gpgme/mkstatus index 08bed64..7e438cc 100755 --- a/gpgme/mkstatus +++ b/gpgme/mkstatus @@ -31,7 +31,7 @@ cat <error) return; @@ -60,34 +60,34 @@ _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_USERID_HINT: + case GPGME_STATUS_USERID_HINT: xfree (ctx->result.passphrase->userid_hint); if (!(ctx->result.passphrase->userid_hint = xtrystrdup (args))) ctx->error = mk_error (Out_Of_Core); break; - case STATUS_BAD_PASSPHRASE: + case GPGME_STATUS_BAD_PASSPHRASE: ctx->result.passphrase->bad_passphrase++; break; - case STATUS_GOOD_PASSPHRASE: + case GPGME_STATUS_GOOD_PASSPHRASE: ctx->result.passphrase->bad_passphrase = 0; break; - case STATUS_NEED_PASSPHRASE: - case STATUS_NEED_PASSPHRASE_SYM: + case GPGME_STATUS_NEED_PASSPHRASE: + case GPGME_STATUS_NEED_PASSPHRASE_SYM: xfree (ctx->result.passphrase->passphrase_info); ctx->result.passphrase->passphrase_info = xtrystrdup (args); if (!ctx->result.passphrase->passphrase_info) ctx->error = mk_error (Out_Of_Core); break; - case STATUS_MISSING_PASSPHRASE: + case GPGME_STATUS_MISSING_PASSPHRASE: DEBUG0 ("missing passphrase - stop\n");; ctx->result.passphrase->no_passphrase = 1; break; - case STATUS_EOF: + case GPGME_STATUS_EOF: if (ctx->result.passphrase->no_passphrase || ctx->result.passphrase->bad_passphrase) ctx->error = mk_error (No_Passphrase); @@ -100,8 +100,8 @@ _gpgme_passphrase_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) } -static const char * -command_handler (void *opaque, GpgStatusCode code, const char *key) +const char * +_gpgme_passphrase_command_handler (void *opaque, GpgmeStatusCode code, const char *key) { GpgmeCtx ctx = opaque; @@ -130,7 +130,7 @@ command_handler (void *opaque, GpgStatusCode code, const char *key) if (!key || !ctx->passphrase_cb) return NULL; - if (code == STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter")) + if (code == GPGME_STATUS_GET_HIDDEN && !strcmp (key, "passphrase.enter")) { const char *userid_hint = ctx->result.passphrase->userid_hint; const char *passphrase_info = ctx->result.passphrase->passphrase_info; @@ -170,6 +170,7 @@ _gpgme_passphrase_start (GpgmeCtx ctx) GpgmeError err = 0; if (ctx->passphrase_cb) - err = _gpgme_engine_set_command_handler (ctx->engine, command_handler, ctx); + err = _gpgme_engine_set_command_handler (ctx->engine, _gpgme_passphrase_command_handler, + ctx, NULL); return err; } diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index b4c3915..c5f7978 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -287,12 +287,12 @@ _gpgme_io_kill (int pid, int hard) * >0 = number of signaled fds */ int -_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds) +_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) { fd_set readfds; fd_set writefds; int any, i, max_fd, n, count; - struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */ + struct timeval timeout = { nonblock ? 0 : 1, 0 }; /* Use a 1s timeout. */ void *dbg_help = NULL; FD_ZERO (&readfds); diff --git a/gpgme/progress.c b/gpgme/progress.c index cb19dad..6a3f74e 100644 --- a/gpgme/progress.c +++ b/gpgme/progress.c @@ -30,7 +30,7 @@ void -_gpgme_progress_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_progress_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { char *p; char *args_cpy; @@ -38,7 +38,7 @@ _gpgme_progress_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) int current = 0; int total = 0; - if (code != STATUS_PROGRESS || !*args || !ctx->progress_cb) + if (code != GPGME_STATUS_PROGRESS || !*args || !ctx->progress_cb) return; args_cpy = xtrystrdup (args); diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 358a7d4..b3b9ca0 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -119,10 +119,14 @@ struct gpg_object_s int fd; int idx; /* Index in fd_data_map */ GpgmeData cb_data; /* hack to get init the above idx later */ - GpgStatusCode code; /* last code */ + GpgmeStatusCode code; /* last code */ char *keyword; /* what has been requested (malloced) */ GpgCommandHandler fnc; void *fnc_value; + /* The kludges never end. This is used to couple command handlers + with output data in edit key mode. */ + GpgmeData linked_data; + int linked_idx; } cmd; struct GpgmeIOCbs io_cbs; @@ -257,6 +261,8 @@ _gpgme_gpg_new (GpgObject *r_gpg) gpg->colon.fd[1] = -1; gpg->cmd.fd = -1; gpg->cmd.idx = -1; + gpg->cmd.linked_data = NULL; + gpg->cmd.linked_idx = -1; gpg->pid = -1; @@ -518,27 +524,29 @@ _gpgme_gpg_set_simple_line_handler ( GpgObject gpg, */ GpgmeError -_gpgme_gpg_set_command_handler ( GpgObject gpg, - GpgCommandHandler fnc, void *fnc_value ) +_gpgme_gpg_set_command_handler (GpgObject gpg, + GpgCommandHandler fnc, void *fnc_value, + GpgmeData linked_data) { - GpgmeData tmp; - GpgmeError err; + GpgmeData tmp; + GpgmeError err; - assert (gpg); - if (gpg->pm.active) - return 0; + assert (gpg); + if (gpg->pm.active) + return 0; - err = gpgme_data_new_with_read_cb ( &tmp, command_cb, gpg ); - if (err) - return err; + err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg); + if (err) + return err; - _gpgme_gpg_add_arg ( gpg, "--command-fd" ); - _gpgme_gpg_add_data (gpg, tmp, -2); - gpg->cmd.cb_data = tmp; - gpg->cmd.fnc = fnc; - gpg->cmd.fnc_value = fnc_value; - gpg->cmd.used = 1; - return 0; + _gpgme_gpg_add_arg ( gpg, "--command-fd" ); + _gpgme_gpg_add_data (gpg, tmp, -2); + gpg->cmd.cb_data = tmp; + gpg->cmd.fnc = fnc; + gpg->cmd.fnc_value = fnc_value; + gpg->cmd.linked_data = linked_data; + gpg->cmd.used = 1; + return 0; } @@ -763,10 +771,18 @@ build_argv (GpgObject gpg) } /* Hack to get hands on the fd later. */ - if (gpg->cmd.used && gpg->cmd.cb_data == a->data) + if (gpg->cmd.used) { - assert (gpg->cmd.idx == -1); - gpg->cmd.idx = datac; + 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; @@ -1001,86 +1017,118 @@ status_cmp (const void *ap, const void *bp) * with status line code we know about and skip all other stuff * without buffering (i.e. without extending the buffer). */ static GpgmeError -read_status ( GpgObject gpg ) +read_status (GpgObject 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 = xtryrealloc (buffer, bufsize); - if ( !buffer ) - return mk_error (Out_Of_Core); + 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 = xtryrealloc (buffer, bufsize); + if (!buffer) + return mk_error (Out_Of_Core); } - - nread = _gpgme_io_read ( gpg->status.fd[0], - buffer+readpos, bufsize-readpos ); - if (nread == -1) - return mk_error(Read_Error); + nread = _gpgme_io_read (gpg->status.fd[0], + buffer + readpos, bufsize-readpos); + if (nread == -1) + return mk_error(Read_Error); - if (!nread) { - gpg->status.eof = 1; - if (gpg->status.fnc) - gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" ); - return 0; + if (!nread) + { + gpg->status.eof = 1; + if (gpg->status.fnc) + gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, ""); + return 0; } - while (nread > 0) { - for (p = buffer + readpos; nread; nread--, p++) { - if ( *p == '\n' ) { - /* (we require that the last line is terminated by a LF) */ - *p = 0; - if (!strncmp (buffer, "[GNUPG:] ", 9 ) - && buffer[9] >= 'A' && buffer[9] <= 'Z' ) { - struct status_table_s t, *r; - char *rest; - - rest = strchr (buffer+9, ' '); - if ( !rest ) - rest = p; /* set to an empty string */ - else - *rest++ = 0; + while (nread > 0) + { + for (p = buffer + readpos; nread; nread--, p++) + { + if (*p == '\n') + { + /* (we require that the last line is terminated by a LF) */ + *p = 0; + if (!strncmp (buffer, "[GNUPG:] ", 9) + && buffer[9] >= 'A' && buffer[9] <= 'Z') + { + struct status_table_s t, *r; + char *rest; + + rest = strchr (buffer + 9, ' '); + if (!rest) + rest = p; /* Set to an empty string. */ + else + *rest++ = 0; - t.name = buffer+9; - /* (the status table as one extra element) */ - r = bsearch ( &t, status_table, DIM(status_table)-1, - sizeof t, status_cmp ); - if ( r ) { - if ( gpg->cmd.used - && ( r->code == STATUS_GET_BOOL - || r->code == STATUS_GET_LINE - || r->code == STATUS_GET_HIDDEN )) { - gpg->cmd.code = r->code; - xfree (gpg->cmd.keyword); - gpg->cmd.keyword = xtrystrdup (rest); - if ( !gpg->cmd.keyword ) - return mk_error (Out_Of_Core); - /* 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"); - - _gpgme_gpg_add_io_cb - (gpg, gpg->cmd.fd, - 0, _gpgme_data_outbound_handler, - gpg->fd_data_map[gpg->cmd.idx].data, - &gpg->fd_data_map[gpg->cmd.idx].tag); - gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd; - gpg->cmd.fd = -1; + 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; + xfree (gpg->cmd.keyword); + gpg->cmd.keyword = xtrystrdup (rest); + if (!gpg->cmd.keyword) + return mk_error (Out_Of_Core); + /* 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"); + + /* 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); + } + + _gpgme_gpg_add_io_cb + (gpg, gpg->cmd.fd, + 0, _gpgme_data_outbound_handler, + gpg->fd_data_map[gpg->cmd.idx].data, + &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 ) { - gpg->status.fnc ( gpg->status.fnc_value, - r->code, rest); + else if (gpg->status.fnc) + { + gpg->status.fnc (gpg->status.fnc_value, + r->code, rest); } - if ( r->code == STATUS_END_STREAM ) { + if (r->code == GPGME_STATUS_END_STREAM) + { if (gpg->cmd.used) { /* XXX We must check if there are any @@ -1094,28 +1142,28 @@ read_status ( GpgObject gpg ) } } } - /* 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 */ + /* 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++; + else + readpos++; } } - /* Update the gpg object. */ - gpg->status.bufsize = bufsize; - gpg->status.buffer = buffer; - gpg->status.readpos = readpos; - return 0; + /* Update the gpg object. */ + gpg->status.bufsize = bufsize; + gpg->status.buffer = buffer; + gpg->status.readpos = readpos; + return 0; } @@ -1399,6 +1447,29 @@ _gpgme_gpg_op_delete (GpgObject gpg, GpgmeKey key, int allow_secret) } +GpgmeError +_gpgme_gpg_op_edit (GpgObject gpg, GpgmeKey key, GpgmeData out) +{ + GpgmeError err; + + err = _gpgme_gpg_add_arg (gpg, "--edit-key"); + if (!err) + err = _gpgme_gpg_add_data (gpg, out, 1); + if (!err) + err = _gpgme_gpg_add_arg (gpg, "--"); + if (!err) + { + const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0); + if (!s) + err = mk_error (Invalid_Key); + else + err = _gpgme_gpg_add_arg (gpg, s); + } + + return err; +} + + static GpgmeError _gpgme_append_gpg_args_from_recipients (GpgObject gpg, const GpgmeRecipients rset) diff --git a/gpgme/rungpg.h b/gpgme/rungpg.h index 2c6fcb7..f0e47f3 100644 --- a/gpgme/rungpg.h +++ b/gpgme/rungpg.h @@ -24,92 +24,9 @@ #include "types.h" - -typedef enum { - STATUS_EOF , - /* mkstatus starts here */ - STATUS_ENTER , - STATUS_LEAVE , - STATUS_ABORT , - - STATUS_GOODSIG , - STATUS_BADSIG , - STATUS_ERRSIG , - - - STATUS_BADARMOR , - - STATUS_RSA_OR_IDEA , - STATUS_KEYEXPIRED , - STATUS_KEYREVOKED , - - STATUS_TRUST_UNDEFINED , - STATUS_TRUST_NEVER , - STATUS_TRUST_MARGINAL , - STATUS_TRUST_FULLY , - STATUS_TRUST_ULTIMATE , - - STATUS_SHM_INFO , - STATUS_SHM_GET , - STATUS_SHM_GET_BOOL , - STATUS_SHM_GET_HIDDEN , - - STATUS_NEED_PASSPHRASE , - STATUS_VALIDSIG , - STATUS_SIG_ID , - STATUS_ENC_TO , - STATUS_NODATA , - STATUS_BAD_PASSPHRASE , - STATUS_NO_PUBKEY , - STATUS_NO_SECKEY , - STATUS_NEED_PASSPHRASE_SYM, - STATUS_DECRYPTION_FAILED , - STATUS_DECRYPTION_OKAY , - STATUS_MISSING_PASSPHRASE , - STATUS_GOOD_PASSPHRASE , - STATUS_GOODMDC , - STATUS_BADMDC , - STATUS_ERRMDC , - STATUS_IMPORTED , - STATUS_IMPORT_RES , - STATUS_FILE_START , - STATUS_FILE_DONE , - STATUS_FILE_ERROR , - - STATUS_BEGIN_DECRYPTION , - STATUS_END_DECRYPTION , - STATUS_BEGIN_ENCRYPTION , - STATUS_END_ENCRYPTION , - - STATUS_DELETE_PROBLEM , - STATUS_GET_BOOL , - STATUS_GET_LINE , - STATUS_GET_HIDDEN , - STATUS_GOT_IT , - STATUS_PROGRESS , - STATUS_SIG_CREATED , - STATUS_SESSION_KEY , - STATUS_NOTATION_NAME , - STATUS_NOTATION_DATA , - STATUS_POLICY_URL , - STATUS_BEGIN_STREAM , - STATUS_END_STREAM , - STATUS_KEY_CREATED , - STATUS_USERID_HINT , - STATUS_UNEXPECTED , - STATUS_INV_RECP , - STATUS_NO_RECP , - STATUS_ALREADY_SIGNED , - STATUS_SIGEXPIRED , - STATUS_EXPSIG , - STATUS_EXPKEYSIG , - STATUS_TRUNCATED , - STATUS_ERROR , -} GpgStatusCode; - -typedef void (*GpgStatusHandler)( GpgmeCtx, GpgStatusCode code, char *args ); +typedef void (*GpgStatusHandler)( GpgmeCtx, GpgmeStatusCode code, char *args ); typedef void (*GpgColonLineHandler)( GpgmeCtx, char *line ); -typedef const char *(*GpgCommandHandler)(void*, GpgStatusCode code, +typedef const char *(*GpgCommandHandler)(void*, GpgmeStatusCode code, const char *keyword); const char *_gpgme_gpg_get_version (void); @@ -122,22 +39,24 @@ void _gpgme_gpg_enable_pipemode ( GpgObject gpg ); GpgmeError _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg ); GpgmeError _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to ); GpgmeError _gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what ); -void _gpgme_gpg_set_status_handler ( GpgObject gpg, - GpgStatusHandler fnc, - void *fnc_value ); +void _gpgme_gpg_set_status_handler (GpgObject gpg, + GpgStatusHandler fnc, + void *fnc_value); GpgmeError _gpgme_gpg_set_colon_line_handler ( GpgObject gpg, GpgColonLineHandler fnc, void *fnc_value ); GpgmeError _gpgme_gpg_set_simple_line_handler ( GpgObject gpg, GpgColonLineHandler fnc, void *fnc_value ); -GpgmeError _gpgme_gpg_set_command_handler ( GpgObject gpg, - GpgCommandHandler fnc, - void *fnc_value ); +GpgmeError _gpgme_gpg_set_command_handler (GpgObject gpg, + GpgCommandHandler fnc, + void *fnc_value, + GpgmeData linked_data); GpgmeError _gpgme_gpg_op_decrypt (GpgObject gpg, GpgmeData ciph, GpgmeData plain); GpgmeError _gpgme_gpg_op_delete (GpgObject gpg, GpgmeKey key, int allow_secret); +GpgmeError _gpgme_gpg_op_edit (GpgObject gpg, GpgmeKey key, GpgmeData out); GpgmeError _gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp, GpgmeData plain, GpgmeData ciph, int use_armor); diff --git a/gpgme/sign.c b/gpgme/sign.c index 8f2fc71..c077c55 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -136,7 +136,7 @@ append_xml_siginfo (GpgmeData *rdh, char *args) } void -_gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { _gpgme_passphrase_status_handler (ctx, code, args); @@ -146,7 +146,7 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: if (ctx->result.sign->okay) { append_xml_siginfo (&ctx->result.sign->xmlinfo, NULL); @@ -157,7 +157,7 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) ctx->error = mk_error (No_Data); /* Hmmm: choose a better error? */ break; - case STATUS_SIG_CREATED: + case GPGME_STATUS_SIG_CREATED: /* FIXME: We have no error return for multiple signatures. */ append_xml_siginfo (&ctx->result.sign->xmlinfo, args); ctx->result.sign->okay = 1; diff --git a/gpgme/trustlist.c b/gpgme/trustlist.c index 2fd4b9c..55fdfdf 100644 --- a/gpgme/trustlist.c +++ b/gpgme/trustlist.c @@ -52,14 +52,14 @@ trust_item_new (void) static void -trustlist_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { if (ctx->error) return; switch (code) { - case STATUS_EOF: + case GPGME_STATUS_EOF: break; default: diff --git a/gpgme/types.h b/gpgme/types.h index 8d23097..1fa4bbf 100644 --- a/gpgme/types.h +++ b/gpgme/types.h @@ -92,5 +92,9 @@ typedef struct genkey_result_s *GenKeyResult; struct keylist_result_s; typedef struct keylist_result_s *KeylistResult; +/*-- edit.c --*/ +struct edit_result_s; +typedef struct edit_result_s *EditResult; + #endif /* TYPES_H */ diff --git a/gpgme/verify.c b/gpgme/verify.c index 1005426..a15a634 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -119,7 +119,7 @@ copy_token (const char *string, char *buffer, size_t length) /* FIXME: Check that we are adding this to the correct signature. */ static void -add_notation (GpgmeCtx ctx, GpgStatusCode code, const char *data) +add_notation (GpgmeCtx ctx, GpgmeStatusCode code, const char *data) { GpgmeData dh = ctx->result.verify->notation; @@ -134,7 +134,7 @@ add_notation (GpgmeCtx ctx, GpgStatusCode code, const char *data) _gpgme_data_append_string (dh, " \n"); } - if (code == STATUS_NOTATION_DATA) + if (code == GPGME_STATUS_NOTATION_DATA) { if (!ctx->result.verify->notation_in_data) _gpgme_data_append_string (dh, " "); @@ -149,13 +149,13 @@ add_notation (GpgmeCtx ctx, GpgStatusCode code, const char *data) ctx->result.verify->notation_in_data = 0; } - if (code == STATUS_NOTATION_NAME) + if (code == GPGME_STATUS_NOTATION_NAME) { _gpgme_data_append_string (dh, " "); _gpgme_data_append_percentstring_for_xml (dh, data); _gpgme_data_append_string (dh, "\n"); } - else if (code == STATUS_POLICY_URL) + else if (code == GPGME_STATUS_POLICY_URL) { _gpgme_data_append_string (dh, " "); _gpgme_data_append_percentstring_for_xml (dh, data); @@ -201,7 +201,7 @@ finish_sig (GpgmeCtx ctx, int stop) void -_gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) +_gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) { char *p; size_t n; @@ -211,11 +211,11 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) return; test_and_allocate_result (ctx, verify); - if (code == STATUS_GOODSIG - || code == STATUS_EXPSIG - || code == STATUS_EXPKEYSIG - || code == STATUS_BADSIG - || code == STATUS_ERRSIG) + if (code == GPGME_STATUS_GOODSIG + || code == GPGME_STATUS_EXPSIG + || code == GPGME_STATUS_EXPKEYSIG + || code == GPGME_STATUS_BADSIG + || code == GPGME_STATUS_ERRSIG) { finish_sig (ctx,0); if (ctx->error) @@ -224,23 +224,23 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) switch (code) { - case STATUS_NODATA: + case GPGME_STATUS_NODATA: ctx->result.verify->status = GPGME_SIG_STAT_NOSIG; break; - case STATUS_GOODSIG: + case GPGME_STATUS_GOODSIG: ctx->result.verify->expstatus = GPGME_SIG_STAT_GOOD; break; - case STATUS_EXPSIG: + case GPGME_STATUS_EXPSIG: ctx->result.verify->expstatus = GPGME_SIG_STAT_GOOD_EXP; break; - case STATUS_EXPKEYSIG: + case GPGME_STATUS_EXPKEYSIG: ctx->result.verify->expstatus = GPGME_SIG_STAT_GOOD_EXPKEY; break; - case STATUS_VALIDSIG: + case GPGME_STATUS_VALIDSIG: ctx->result.verify->status = GPGME_SIG_STAT_GOOD; i = copy_token (args, ctx->result.verify->fpr, DIM(ctx->result.verify->fpr)); @@ -255,14 +255,14 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) ctx->result.verify->exptimestamp = strtoul (p, NULL, 10); break; - case STATUS_BADSIG: + case GPGME_STATUS_BADSIG: ctx->result.verify->status = GPGME_SIG_STAT_BAD; /* Store the keyID in the fpr field. */ copy_token (args, ctx->result.verify->fpr, DIM(ctx->result.verify->fpr)); break; - case STATUS_ERRSIG: + case GPGME_STATUS_ERRSIG: /* The return code is the 6th argument, if it is 9, the problem is a missing key. Note that this is not emitted by gpgsm */ for (p = args, i = 0; p && *p && i < 5; i++) @@ -281,38 +281,38 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) DIM(ctx->result.verify->fpr)); break; - case STATUS_NOTATION_NAME: - case STATUS_NOTATION_DATA: - case STATUS_POLICY_URL: + case GPGME_STATUS_NOTATION_NAME: + case GPGME_STATUS_NOTATION_DATA: + case GPGME_STATUS_POLICY_URL: add_notation (ctx, code, args); break; - case STATUS_TRUST_UNDEFINED: + case GPGME_STATUS_TRUST_UNDEFINED: ctx->result.verify->validity = GPGME_VALIDITY_UNKNOWN; copy_token (args, ctx->result.verify->trust_errtok, DIM(ctx->result.verify->trust_errtok)); break; - case STATUS_TRUST_NEVER: + case GPGME_STATUS_TRUST_NEVER: ctx->result.verify->validity = GPGME_VALIDITY_NEVER; copy_token (args, ctx->result.verify->trust_errtok, DIM(ctx->result.verify->trust_errtok)); break; - case STATUS_TRUST_MARGINAL: + case GPGME_STATUS_TRUST_MARGINAL: if (ctx->result.verify->status == GPGME_SIG_STAT_GOOD) ctx->result.verify->validity = GPGME_VALIDITY_MARGINAL; copy_token (args, ctx->result.verify->trust_errtok, DIM(ctx->result.verify->trust_errtok)); break; - case STATUS_TRUST_FULLY: - case STATUS_TRUST_ULTIMATE: + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: if (ctx->result.verify->status == GPGME_SIG_STAT_GOOD) ctx->result.verify->validity = GPGME_VALIDITY_FULL; break; - case STATUS_END_STREAM: + case GPGME_STATUS_END_STREAM: break; - case STATUS_ERROR: + case GPGME_STATUS_ERROR: /* Generic error, we need this for gpgsm (and maybe for gpg in future) to get error descriptions. */ if (is_token (args, "verify.findkey", &n) && n) @@ -332,7 +332,7 @@ _gpgme_verify_status_handler (GpgmeCtx ctx, GpgStatusCode code, char *args) } break; - case STATUS_EOF: + case GPGME_STATUS_EOF: finish_sig (ctx,1); /* FIXME: Put all notation data into one XML fragment. */ diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index 602be1f..6d4957f 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -985,7 +985,7 @@ _gpgme_io_kill ( int pid, int hard ) * >0 = number of signaled fds */ int -_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) +_gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds, int nonblock ) { HANDLE waitbuf[MAXIMUM_WAIT_OBJECTS]; int waitidx[MAXIMUM_WAIT_OBJECTS]; @@ -1056,7 +1056,7 @@ _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds ) if (!any) return 0; - code = WaitForMultipleObjects ( nwait, waitbuf, 0, 1000); + 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 diff --git a/gpgme/wait.c b/gpgme/wait.c index 0cb476e..69c0a11 100644 --- a/gpgme/wait.c +++ b/gpgme/wait.c @@ -152,7 +152,7 @@ do_select (fd_table_t fdt) int any = 0; LOCK (fdt->lock); - n = _gpgme_io_select (fdt->fds, fdt->size); + n = _gpgme_io_select (fdt->fds, fdt->size, 0); if (n <= 0) { -- 2.26.2