Allow exporting keys to a keyserver.
-Noteworthy changes in version 1.1.9
+Noteworthy changes in version 1.2.0
------------------------------------------------
* New encryption flag GPGME_ENCRYPT_NO_ENCRYPT_TO to disable default
* New functions gpgme_io_read and gpgme_io_write for use with
gpgme_passphrase_cb_t and gpgme_edit_cb_t functions.
-
* Interface changes relative to the 1.1.7 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_EPHEMERAL NEW.
gpgme_op_assuan_transact_start NEW.
gpgme_op_assuan_transact NEW.
gpgme_op_assuan_result NEW.
+ gpgme_op_import_keys NEW.
+ gpgme_op_import_keys_start NEW.
gpgme_subkey_t EXTENDED: New fields is_cardkey, card_number.
GPGME_ENCRYPT_NO_ENCRYPT_TO NEW.
gpgme_check_version CHANGED: Is now a macro.
gpgme_new EXTENDED: More failure codes.
gpgme_io_read NEW.
gpgme_io_write NEW.
+ gpgme_result_ref NEW.
+ gpgme_result_unref NEW.
+ gpgme_export_mode_t NEW.
+ gpgme_export_ext_start EXTENDED: Arg RESERVED is now a MODE flag.
+ gpgme_op_export EXTENDED: Arg RESERVED is now a MODE flag.
+ gpgme_op_export_ext_start EXTENDED: Arg RESERVED is now a MODE flag.
+ gpgme_op_export_ext EXTENDED: Arg RESERVED is now a MODE flag.
+ gpgme_op_export_keys_start NEW.
+ gpgme_op_export_keys NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Hey Emacs, this is -*- outline -*- mode!
+Hey Emacs, this is -*- org -*- mode!
* IMPORTANT
** When using descriptor passing, we need to set the fd to blocking before
(see edit.c::command_handler).
** I/O and User Data could be made extensible. But this can be done
without breaking the ABI hopefully.
-* All enums that should be enums need to have a maximum value to ensure
+** All enums that should be enums need to have a maximum value to ensure
a certain minimum width for extensibility.
** Compatibility interfaces that can be removed in future versions:
*** gpgme_data_new_from_filepart
application can then do whatever is required. There are other
usages too. This notfication system should be independent of any
contextes of course.
+
+ Not sure whether this is still required. GPGME_PROTOCOL_ASSUAN is
+ sufficient for this.
+
** --learn-code support
This might be integrated with import. we still need to work out how
- to learn a card when gpg and gpgsm have support for smartcards.
+ to learn a card when gpg and gpgsm have support for smartcards. In
+ GPA we currently invoke gpg directly.
+
** Might need a stat() for data objects and use it for length param to gpg.
** Implement support for photo ids.
** Allow selection of subkeys
*** Allow to export secret keys.
Rejected because this is conceptually flawed. Secret keys on a
smart card can not be exported, for example.
+ May eventually e supproted with a keywrapping system.
*** Selecting the key ring, setting the version or comment in output.
Rejected because the naive implementation is engine specific, the
configuration is part of the engine's configuration or readily
(it's an internal error, as select_protocol checks already).
** When server mode is implemented properly, more care has to be taken to
release all resources on error (for example to free assuan_cmd).
+** op_import_keys and op_export_keys have a limit ion the number of keys.
+ This is because we pass them in gpg via the command line and gpgsm
+ via an assuan control line. We should pipe them instead and maybe
+ change gpg/gpgsm to not put them in memory.
+
* GPG breakage:
** gpg 1.4.2 lacks error reporting if sign/encrypt with revoked key.
** gpg 1.4.2 does crappy error reporting (namely none at all) when
+2009-06-12 Werner Koch <wk@g10code.com>
+
+ * assuan-pipe-connect.c (_gpgme_io_spawn): Change prototype.
+ (pipe_connect_gpgme): Pass a flags arg.
+
2009-04-08 Marcus Brinkmann <marcus@g10code.de>
* assuan.h (_gpgme_io_socket): New prototype.
int _gpgme_io_pipe (int filedes[2], int inherit_idx);
-int _gpgme_io_spawn (const char *path, char *const argv[],
+int _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
struct spawn_fd_item_s *fd_list, pid_t *r_pid);
#endif
child_fds[nr].dup_to = -1;
/* Start the process. */
- res = _gpgme_io_spawn (name, (char *const *) argv, child_fds, NULL);
+ res = _gpgme_io_spawn (name, (char *const *) argv, 0, child_fds, NULL);
if (res == -1)
{
_assuan_log_printf ("CreateProcess failed: %s\n", strerror (errno));
+2009-06-16 Werner Koch <wk@g10code.com>
+
+ * gpgme.texi (Exporting Keys): Document gpgme_op_export_keys.
+ (Importing Keys): Document gpgme_op_import_keys.
+
2009-05-28 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Library Version Check): Document selftest error.
@cindex key, export
@cindex key ring, export from
-@deftypefun gpgme_error_t gpgme_op_export (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}})
+Exporting keys means the same as running @command{gpg} with the command
+@option{--export}. However, a mode flag can be used to change the way
+the export works. The available mode flags are described below, they
+may be or-ed together.
+
+@table @code
+
+@item GPGME_EXPORT_MODE_EXTERN
+If this bit is set, the output is send directly to the default
+keyserver. This is currently only allowed for OpenPGP keys. It is good
+practise to not send more than a few dozens key to a keyserver at one
+time. Using this flag requires that the @var{keydata} argument of the
+export function is set to @code{NULL}.
+
+@end table
+
+
+
+@deftypefun gpgme_error_t gpgme_op_export (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export} extracts public keys and returns
them in the data buffer @var{keydata}. The output format of the key
data returned is determined by the @acronym{ASCII} armor attribute set
Otherwise, @var{pattern} contains an engine specific expression that
is used to limit the list to all keys matching the pattern.
-@var{reserved} is reserved for future use and must be @code{0}.
+@var{mode} is usually 0; other values are described above.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation completed successfully, @code{GPG_ERR_INV_VALUE} if
errors that are reported by the crypto engine support routines.
@end deftypefun
-@deftypefun gpgme_error_t gpgme_op_export_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}})
+@deftypefun gpgme_error_t gpgme_op_export_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_start} initiates a
@code{gpgme_op_export} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
if @var{keydata} is not a valid empty data buffer.
@end deftypefun
-@deftypefun gpgme_error_t gpgme_op_export_ext (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}})
+@deftypefun gpgme_error_t gpgme_op_export_ext (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export} extracts public keys and returns
them in the data buffer @var{keydata}. The output format of the key
data returned is determined by the @acronym{ASCII} armor attribute set
array of strings that are used to limit the list to all keys matching
at least one of the patterns verbatim.
-@var{reserved} is reserved for future use and must be @code{0}.
+@var{mode} is usually 0; other values are described above.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation completed successfully, @code{GPG_ERR_INV_VALUE} if
errors that are reported by the crypto engine support routines.
@end deftypefun
-@deftypefun gpgme_error_t gpgme_op_export_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}})
+@deftypefun gpgme_error_t gpgme_op_export_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_ext_start} initiates a
@code{gpgme_op_export_ext} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_export_keys (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t keys[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
+The function @code{gpgme_op_export_keys} extracts public keys and returns
+them in the data buffer @var{keydata}. The output format of the key
+data returned is determined by the @acronym{ASCII} armor attribute set
+for the context @var{ctx}, or, if that is not set, by the encoding
+specified for @var{keydata}.
+
+The keys to export are taken form the @code{NULL} terminated array
+@var{keys}. Only keys of the the currently selected protocol of
+@var{ctx} which do have a fingerprint set are considered for export.
+Other keys specified by the @var{keys} are ignored. In particular
+OpenPGP keys retrieved via an external key listing are not included.
+
+@var{mode} is usually 0; other values are described above.
+
+The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+operation completed successfully, @code{GPG_ERR_INV_VALUE} if
+@var{keydata} is not a valid empty data buffer, @code{GPG_ERR_NO_DATA}
+if no useful keys are in @var{keys} and passes through any errors that
+are reported by the crypto engine support routines.
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_export_keys_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{keys}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
+The function @code{gpgme_op_export_keys_start} initiates a
+@code{gpgme_op_export_ext} operation. It can be completed by calling
+@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
+
+The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+operation could be started successfully, and @code{GPG_ERR_INV_VALUE}
+if @var{keydata} is not a valid empty data buffer, @code{GPG_ERR_NO_DATA}
+if no useful keys are in @var{keys} and passes through any errors that
+are reported by the crypto engine support routines.
+@end deftypefun
+
+
@node Importing Keys
@subsection Importing Keys
@cindex key, import
@cindex key ring, import to
+Importing keys means the same as running @command{gpg} with the command
+@option{--import}.
+
+
@deftypefun gpgme_error_t gpgme_op_import (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_import} adds the keys in the data buffer
@var{keydata} to the key ring of the crypto engine used by @var{ctx}.
and @code{GPG_ERR_NO_DATA} if @var{keydata} is an empty data buffer.
@end deftypefun
+@deftypefun gpgme_error_t gpgme_op_import_keys (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
+The function @code{gpgme_op_import_keys} adds the keys described by the
+@code{NULL} terminated array @var{keys} to the key ring of the crypto
+engine used by @var{ctx}. This function is the general interface to
+move a key from one crypto engine to another as long as they are
+compatible. In particular it is used to actually import and make keys
+permanent which have been retrieved from an external source (i.e. using
+@code{GPGME_KEYLIST_MODE_EXTERN}). @footnote{Thus it is a replacement
+for the usual workaround of exporting and then importing a key to make
+an X.509 key permanent.}
+
+Only keys of the the currently selected protocol of @var{ctx} are
+considered for import. Other keys specified by the @var{keys} are
+ignored. As of now all considered keys must have been retrieved using
+the same method, that is the used key listing mode must be identical.
+
+After the operation completed successfully, the result can be
+retrieved with @code{gpgme_op_import_result}.
+
+The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+import was completed successfully, @code{GPG_ERR_INV_VALUE} if
+@var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
+@code{GPG_ERR_CONFLICT} if the key listing mode does not match, and
+@code{GPG_ERR_NO_DATA} if no keys are considered for export.
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_import_keys_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
+The function @code{gpgme_op_import_keys_start} initiates a
+@code{gpgme_op_import_keys} operation. It can be completed by calling
+@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
+
+The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+import was completed successfully, @code{GPG_ERR_INV_VALUE} if
+@var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
+@code{GPG_ERR_CONFLICT} if the key listing mode does not match, and
+@code{GPG_ERR_NO_DATA} if no keys are considered for export.
+@end deftypefun
+
@deftp {Data type} {gpgme_import_status_t}
This is a pointer to a structure used to store a part of the result of
a @code{gpgme_op_import} operation. For each considered key one
+2009-06-16 Werner Koch <wk@g10code.com>
+
+ * gpgme.h.in (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
+ * gpgme.def, libgpgme.vers: Add them.
+ * export.c (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
+ (export_keys_start): New.
+
+ * gpgme.h.in (gpgme_export_mode_t, GPGME_EXPORT_MODE_EXTERN): New.
+ (gpgme_op_export_start, gpgme_op_export, gpgme_op_export_ext_start)
+ (gpgme_op_export_ext): Change arg RESERVED to MODE of new
+ compatible type.
+ * export.c (gpgme_export_ext_start, gpgme_op_export)
+ (gpgme_op_export_ext_start, gpgme_op_export_ext): Ditto.
+ (export_start): Ditto.
+ * engine.c (_gpgme_engine_op_export): Ditto.
+ * engine-backend.h (struct engine_ops): Ditto.
+ * engine-gpgsm.c (gpgsm_export, gpgsm_export_ext): Ditto.
+ * engine-gpg.c (gpg_export, gpg_export_ext): Ditto. Implement
+ mode EXTERN.
+ (gpg_export, gpg_export_ext): Factor common code out to ..
+ (export_common): .. this.
+
+ * gpgme.h.in (gpgme_op_import_keys_start, gpgme_op_import_keys): New.
+ * gpgme.def, libgpgme.vers: Add them.
+ * import.c (gpgme_op_import_keys_start, gpgme_op_import_keys): New.
+ (_gpgme_op_import_keys_start): New.
+ * engine.c (_gpgme_engine_op_import): Add arg KEYARRAY.
+ * engine-backend.h (struct engine_ops): Ditto.
+ * engine-gpgsm.c (gpgsm_import): Ditto. Not functional.
+ * engine-gpg.c (gpg_import): Ditto. Implement it.
+
2009-06-15 Marcus Brinkmann <marcus@g10code.de>
* gpgme.h.in (gpgme_result_ref, gpgme_result_unref): Add
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,
+ gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor);
gpgme_error_t (*export_ext) (void *engine, const char *pattern[],
- unsigned int reserved, gpgme_data_t keydata,
+ gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor);
gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor,
gpgme_data_t pubkey, gpgme_data_t seckey);
- gpgme_error_t (*import) (void *engine, gpgme_data_t keydata);
+ gpgme_error_t (*import) (void *engine, gpgme_data_t keydata,
+ gpgme_key_t *keyarray);
gpgme_error_t (*keylist) (void *engine, const char *pattern,
int secret_only, gpgme_keylist_mode_t mode);
gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[],
/* 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
+ a key KEY. If the Code passed to FNC is 0, the function may release
resources associated with the returned value from another call. To
match such a second call to a first call, the returned value from
the first call is passed as keyword. */
static gpgme_error_t
-gpg_export (void *engine, const char *pattern, unsigned int reserved,
- gpgme_data_t keydata, int use_armor)
+export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
+ 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);
+ if ((mode & ~GPGME_EXPORT_MODE_EXTERN))
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
- err = add_arg (gpg, "--export");
- if (!err && use_armor)
- err = add_arg (gpg, "--armor");
- if (!err)
- err = add_data (gpg, keydata, 1, 1);
+ if ((mode & GPGME_EXPORT_MODE_EXTERN))
+ {
+ err = add_arg (gpg, "--send-keys");
+ }
+ else
+ {
+ err = add_arg (gpg, "--export");
+ if (!err && use_armor)
+ err = add_arg (gpg, "--armor");
+ if (!err)
+ err = add_data (gpg, keydata, 1, 1);
+ }
if (!err)
err = add_arg (gpg, "--");
+ return err;
+}
+
+
+static gpgme_error_t
+gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
+ gpgme_data_t keydata, int use_armor)
+{
+ engine_gpg_t gpg = engine;
+ gpgme_error_t err;
+
+ err = export_common (gpg, mode, keydata, use_armor);
+
if (!err && pattern && *pattern)
err = add_arg (gpg, pattern);
static gpgme_error_t
-gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved,
+gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor)
{
engine_gpg_t gpg = engine;
gpgme_error_t err;
- 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, "--");
+ err = export_common (gpg, mode, keydata, use_armor);
if (pattern)
{
static gpgme_error_t
-gpg_import (void *engine, gpgme_data_t keydata)
+gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
{
engine_gpg_t gpg = engine;
gpgme_error_t err;
+ int idx;
- err = add_arg (gpg, "--import");
- if (!err)
- err = add_arg (gpg, "--");
- if (!err)
- err = add_data (gpg, keydata, -1, 0);
+ if (keydata && keyarray)
+ gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
+
+ if (keyarray)
+ {
+ err = add_arg (gpg, "--recv-keys");
+ if (!err)
+ err = add_arg (gpg, "--");
+ for (idx=0; !err && keyarray[idx]; idx++)
+ {
+ if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
+ ;
+ else if (!keyarray[idx]->subkeys)
+ ;
+ else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
+ err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
+ else if (*keyarray[idx]->subkeys->keyid)
+ err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
+ }
+ }
+ else
+ {
+ err = add_arg (gpg, "--import");
+ if (!err)
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, keydata, -1, 0);
+ }
if (!err)
err = start (gpg);
static gpgme_error_t
-gpgsm_export (void *engine, const char *pattern, unsigned int reserved,
+gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor)
{
engine_gpgsm_t gpgsm = engine;
gpgme_error_t err = 0;
char *cmd;
- if (!gpgsm || reserved)
+ if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (mode)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (!pattern)
pattern = "";
static gpgme_error_t
-gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved,
+gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor)
{
engine_gpgsm_t gpgsm = engine;
int length = 7 + 1;
char *linep;
- if (!gpgsm || reserved)
+ if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE);
+ if (mode)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
if (pattern && *pattern)
{
const char **pat = pattern;
static gpgme_error_t
-gpgsm_import (void *engine, gpgme_data_t keydata)
+gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
{
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_data_enc (gpgsm->input_cb.data));
- if (err)
- return err;
- gpgsm_clear_fd (gpgsm, OUTPUT_FD);
- gpgsm_clear_fd (gpgsm, MESSAGE_FD);
- gpgsm->inline_data = NULL;
+ if (keydata && keyarray)
+ gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
+
+ if (keyarray)
+ {
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+ }
+ else
+ {
+ gpgsm->input_cb.data = keydata;
+ err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
+ if (err)
+ return err;
+ gpgsm_clear_fd (gpgsm, OUTPUT_FD);
+ gpgsm_clear_fd (gpgsm, MESSAGE_FD);
+ gpgsm->inline_data = NULL;
+ }
err = start (gpgsm, "IMPORT");
return err;
gpgme_error_t
_gpgme_engine_op_export (engine_t engine, const char *pattern,
- unsigned int reserved, gpgme_data_t keydata,
+ gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor)
{
if (!engine)
if (!engine->ops->export)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- return (*engine->ops->export) (engine->engine, pattern, reserved,
+ return (*engine->ops->export) (engine->engine, pattern, mode,
keydata, use_armor);
}
gpgme_error_t
-_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
+_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
+ gpgme_key_t *keyarray)
{
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);
+ return (*engine->ops->import) (engine->engine, keydata, keyarray);
}
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_export_mode_t mode,
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_export_mode_t mode,
gpgme_data_t keydata,
int use_armor);
gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
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_data_t keydata,
+ gpgme_key_t *keyarray);
gpgme_error_t _gpgme_engine_op_keylist (engine_t engine,
const char *pattern,
int secret_only,
#if HAVE_CONFIG_H
#include <config.h>
#endif
+#include <stdlib.h>
+#include <string.h>
#include "gpgme.h"
#include "context.h"
static gpgme_error_t
export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
- unsigned int reserved, gpgme_data_t keydata)
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
{
gpgme_error_t err;
- if (!keydata)
- return gpg_error (GPG_ERR_INV_VALUE);
+ if ((mode & ~(GPGME_EXPORT_MODE_EXTERN)))
+ return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */
+
+
+ if ((mode & GPGME_EXPORT_MODE_EXTERN))
+ {
+ if (keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
+ else
+ {
+ if (!keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
err = _gpgme_op_reset (ctx, synchronous);
if (err)
_gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
- return _gpgme_engine_op_export (ctx->engine, pattern, reserved, keydata,
+ return _gpgme_engine_op_export (ctx->engine, pattern, mode, keydata,
ctx->use_armor);
}
-/* Export the keys listed in RECP into KEYDATA. */
+/* Export the keys listed in 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_export_mode_t mode, gpgme_data_t keydata)
{
- return export_start (ctx, 0, pattern, reserved, keydata);
+ return export_start (ctx, 0, pattern, mode, keydata);
}
-/* Export the keys listed in RECP into KEYDATA. */
+/* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t
-gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved,
- gpgme_data_t keydata)
+gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
{
- gpgme_error_t err = export_start (ctx, 1, pattern, reserved, keydata);
+ gpgme_error_t err = export_start (ctx, 1, pattern, mode, keydata);
if (!err)
err = _gpgme_wait_one (ctx);
return err;
\f
static gpgme_error_t
export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
- unsigned int reserved, gpgme_data_t keydata)
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
{
gpgme_error_t err;
- if (!keydata)
- return gpg_error (GPG_ERR_INV_VALUE);
+ if ((mode & ~(GPGME_EXPORT_MODE_EXTERN)))
+ return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */
+
+ if ((mode & GPGME_EXPORT_MODE_EXTERN))
+ {
+ if (keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
+ else
+ {
+ if (!keydata)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
err = _gpgme_op_reset (ctx, synchronous);
if (err)
_gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
- return _gpgme_engine_op_export_ext (ctx->engine, pattern, reserved, keydata,
+ return _gpgme_engine_op_export_ext (ctx->engine, pattern, mode, keydata,
ctx->use_armor);
}
-/* Export the keys listed in RECP into KEYDATA. */
+/* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t
gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[],
- unsigned int reserved, gpgme_data_t keydata)
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
{
- return export_ext_start (ctx, 0, pattern, reserved, keydata);
+ return export_ext_start (ctx, 0, pattern, mode, keydata);
}
-/* Export the keys listed in RECP into KEYDATA. */
+/* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t
gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
- unsigned int reserved, gpgme_data_t keydata)
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
+{
+ gpgme_error_t err = export_ext_start (ctx, 1, pattern, mode, keydata);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+
+\f
+
+static gpgme_error_t
+export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[],
+ gpgme_export_mode_t mode, gpgme_data_t keydata)
+{
+ gpgme_error_t err;
+ int nkeys, idx;
+ char **pattern;
+
+ if (!keys)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ /* Create a list of pattern from the keys. */
+ for (idx=nkeys=0; keys[idx]; idx++)
+ if (keys[idx]->protocol == ctx->protocol)
+ nkeys++;
+ if (!nkeys)
+ return gpg_error (GPG_ERR_NO_DATA);
+
+ pattern = calloc (nkeys+1, sizeof *pattern);
+ if (!pattern)
+ return gpg_error_from_syserror ();
+
+ for (idx=nkeys=0; keys[idx]; idx++)
+ if (keys[idx]->protocol == ctx->protocol
+ && keys[idx]->subkeys
+ && keys[idx]->subkeys->fpr
+ && *keys[idx]->subkeys->fpr)
+ {
+ pattern[nkeys] = strdup (keys[idx]->subkeys->fpr);
+ if (!pattern[nkeys])
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ nkeys++;
+ }
+
+
+ /* Pass on to the regular function. */
+ err = export_ext_start (ctx, synchronous, (const char**)pattern,
+ mode, keydata);
+
+ leave:
+ for (idx=0; pattern[idx]; idx++)
+ free (pattern[idx]);
+ free (pattern);
+
+ return err;
+}
+
+
+/* Export the keys from the array KEYS into KEYDATA. Only keys of the
+ current protocol are exported and only those which have a
+ fingerprint set; that is keys received with some external search
+ methods are silently skipped. */
+gpgme_error_t
+gpgme_op_export_keys_start (gpgme_ctx_t ctx,
+ gpgme_key_t keys[],
+ gpgme_export_mode_t mode,
+ gpgme_data_t keydata)
{
- gpgme_error_t err = export_ext_start (ctx, 1, pattern, reserved, keydata);
+ return export_keys_start (ctx, 0, keys, mode, keydata);
+}
+
+gpgme_error_t
+gpgme_op_export_keys (gpgme_ctx_t ctx,
+ gpgme_key_t keys[],
+ gpgme_export_mode_t mode,
+ gpgme_data_t keydata)
+{
+ gpgme_error_t err = export_keys_start (ctx, 1, keys, mode, keydata);
if (!err)
err = _gpgme_wait_one (ctx);
return err;
}
+
gpgme_release_ref @138
gpgme_release_unref @139
+ gpgme_op_import_keys @140
+ gpgme_op_import_keys_start @141
+ gpgme_op_export_keys @142
+ gpgme_op_export_keys_start @143
+
; END
typedef unsigned int gpgme_keylist_mode_t;
+\f
+/* The available export mode flags. */
+#define GPGME_EXPORT_MODE_EXTERN 2
+
+typedef unsigned int gpgme_export_mode_t;
+
\f
/* Flags for the audit log functions. */
#define GPGME_AUDITLOG_HTML 1
gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
int *nr) _GPGME_DEPRECATED;
+/* Import the keys from the array KEYS into the keyring. */
+gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]);
+gpgme_error_t gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t keys[]);
+
+
\f
/* 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_export_mode_t mode,
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_export_mode_t mode,
+ gpgme_data_t keydata);
gpgme_error_t gpgme_op_export_ext_start (gpgme_ctx_t ctx,
const char *pattern[],
- unsigned int reserved,
+ gpgme_export_mode_t mode,
gpgme_data_t keydata);
gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
- unsigned int reserved,
+ gpgme_export_mode_t mode,
gpgme_data_t keydata);
+/* Export the keys from the array KEYS into KEYDATA. */
+gpgme_error_t gpgme_op_export_keys_start (gpgme_ctx_t ctx,
+ gpgme_key_t keys[],
+ gpgme_export_mode_t mode,
+ gpgme_data_t keydata);
+gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
+ gpgme_key_t keys[],
+ gpgme_export_mode_t mode,
+ gpgme_data_t keydata);
+
+
\f
/* Key generation. */
struct _gpgme_op_genkey_result
_gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
- return _gpgme_engine_op_import (ctx->engine, keydata);
+ return _gpgme_engine_op_import (ctx->engine, keydata, NULL);
}
}
+\f
+static gpgme_error_t
+_gpgme_op_import_keys_start (gpgme_ctx_t ctx, int synchronous,
+ gpgme_key_t *keys)
+{
+ gpgme_error_t err;
+ void *hook;
+ op_data_t opd;
+ int idx, firstidx, nkeys;
+
+ 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 (!keys)
+ return gpg_error (GPG_ERR_NO_DATA);
+
+ for (idx=nkeys=0, firstidx=-1; keys[idx]; idx++)
+ {
+ /* We only consider keys of the current protocol. */
+ if (keys[idx]->protocol != ctx->protocol)
+ continue;
+ if (firstidx == -1)
+ firstidx = idx;
+ /* If a key has been found using a different key listing mode,
+ we bail out. This makes the processing easier. Fixme: To
+ allow a mix of keys we would need to sort them by key listing
+ mode and start two import operations one after the other. */
+ if (keys[idx]->keylist_mode != keys[firstidx]->keylist_mode)
+ return gpg_error (GPG_ERR_CONFLICT);
+ nkeys++;
+ }
+ if (!nkeys)
+ 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, NULL, keys);
+}
+
+
+/* Asynchronous version of gpgme_op_import_key. */
+gpgme_error_t
+gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys)
+{
+ return _gpgme_op_import_keys_start (ctx, 0, keys);
+}
+
+
+/* Import the keys from the array KEYS into the keyring. This
+ function allows to move a key from one engine to another as long as
+ they are compatible. In particular it is used to actually import
+ keys retrieved from an external source (i.e. using
+ GPGME_KEYLIST_MODE_EXTERN). It replaces the old workaround of
+ exporting and then importing a key as used to make an X.509 key
+ permanent. This function automagically does the right thing.
+
+ KEYS is a NULL terminated array of gpgme key objects. The result
+ is the usual import result structure. Only keys matching the
+ current protocol are imported; other keys are ignored. */
+gpgme_error_t
+gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t *keys)
+{
+ gpgme_error_t err = _gpgme_op_import_keys_start (ctx, 1, keys);
+ if (!err)
+ err = _gpgme_wait_one (ctx);
+ return err;
+}
+
+
+/* Deprecated interface. */
gpgme_error_t
gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr)
{
gpgme_result_ref;
gpgme_result_unref;
+
+ gpgme_op_import_keys;
+ gpgme_op_import_keys_start;
+ gpgme_op_export_keys;
+ gpgme_op_export_keys_start;
};
+2009-06-16 Werner Koch <wk@g10code.com>
+
+ * gpg/pgp-export.c, gpg/pgp-keylist.c: New.
+
2009-06-09 Werner Koch <wk@g10code.com>
* gpg/Makefile.am (./pubring.gpg): Ignore errors in case of
* gpg/mkdemodirs: Renamed to ...
* gpg/mkdemodirs.in: ... here.
- * gpg/mkdemodirs.in (GPG): Derive value from @GPG@ instead of hard-coding "gpg".
+ * gpg/mkdemodirs.in (GPG): Derive value from @GPG@ instead of
+ hard-coding "gpg".
2009-02-24 Werner Koch <wk@g10code.com>
t_thread1_LDADD = ../../src/libgpgme-pthread.la
# We don't run t-genkey in the test suite, because it takes too long
-noinst_PROGRAMS = $(TESTS) t-genkey
+# The other programs are used for debugging.
+noinst_PROGRAMS = $(TESTS) t-genkey pgp-keylist pgp-export
mkdemodirs: mkdemodirs.in Makefile
sed -e 's,[@]GPG[@],$(GPG),g' < $(srcdir)/mkdemodirs.in > mkdemodirs
--- /dev/null
+/* pgp-export.c - Helper to run an export command
+ Copyright (C) 2008, 2009 g10 Code GmbH
+
+ This file is part of GPGME.
+
+ GPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ GPGME is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* We need to include config.h so that we know whether we are building
+ with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#define PGM "pgp-export"
+
+#include "t-support.h"
+
+
+static int verbose;
+
+
+static const char *
+nonnull (const char *s)
+{
+ return s? s :"[none]";
+}
+
+
+static int
+show_usage (int ex)
+{
+ fputs ("usage: " PGM " [options] USERIDS\n\n"
+ "Options:\n"
+ " --verbose run in verbose mode\n"
+ " --extern send keys to the keyserver (TAKE CARE!)\n"
+ , stderr);
+ exit (ex);
+}
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ gpgme_error_t err;
+ gpgme_ctx_t ctx;
+ gpgme_key_t key;
+ gpgme_keylist_result_t result;
+ gpgme_key_t keyarray[100];
+ int keyidx = 0;
+ gpgme_data_t out;
+ gpgme_export_mode_t mode = 0;
+
+ if (argc)
+ { argc--; argv++; }
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ show_usage (0);
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--extern"))
+ {
+ mode |= GPGME_KEYLIST_MODE_EXTERN;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ show_usage (1);
+
+ }
+
+ if (!argc)
+ show_usage (1);
+
+ init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
+ gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+
+ /* Lookup the keys. */
+ err = gpgme_op_keylist_ext_start (ctx, (const char**)argv, 0, 0);
+ fail_if_err (err);
+
+ while (!(err = gpgme_op_keylist_next (ctx, &key)))
+ {
+ printf ("keyid: %s (fpr: %s)\n",
+ key->subkeys?nonnull (key->subkeys->keyid):"?",
+ key->subkeys?nonnull (key->subkeys->fpr):"?");
+
+ if (keyidx < DIM (keyarray)-1)
+ keyarray[keyidx++] = key;
+ else
+ {
+ fprintf (stderr, PGM": too many keys"
+ "- skipping this key\n");
+ gpgme_key_unref (key);
+ }
+ }
+ if (gpg_err_code (err) != GPG_ERR_EOF)
+ fail_if_err (err);
+ err = gpgme_op_keylist_end (ctx);
+ fail_if_err (err);
+ keyarray[keyidx] = NULL;
+
+ result = gpgme_op_keylist_result (ctx);
+ if (result->truncated)
+ {
+ fprintf (stderr, PGM ": key listing unexpectedly truncated\n");
+ exit (1);
+ }
+
+ /* Now for the actual export. */
+ if ((mode & GPGME_KEYLIST_MODE_EXTERN))
+ printf ("sending keys to keyserver\n");
+
+ err = gpgme_data_new (&out);
+ fail_if_err (err);
+
+ gpgme_set_armor (ctx, 1);
+ err = gpgme_op_export_keys (ctx, keyarray, mode,
+ (mode & GPGME_KEYLIST_MODE_EXTERN)? NULL:out);
+ fail_if_err (err);
+
+ fflush (NULL);
+ if (!(mode & GPGME_KEYLIST_MODE_EXTERN))
+ {
+ fputs ("Begin Result:\n", stdout);
+ print_data (out);
+ fputs ("End Result.\n", stdout);
+ }
+
+ /* Cleanup. */
+ gpgme_data_release (out);
+
+ for (keyidx=0; keyarray[keyidx]; keyidx++)
+ gpgme_key_unref (keyarray[keyidx]);
+
+ gpgme_release (ctx);
+ return 0;
+}
--- /dev/null
+/* pgp-keylist.c - Helper to show a key listing.
+ Copyright (C) 2008, 2009 g10 Code GmbH
+
+ This file is part of GPGME.
+
+ GPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ GPGME is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* We need to include config.h so that we know whether we are building
+ with large file system (LFS) support. */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#define PGM "pgp-keylist"
+
+#include "t-support.h"
+
+
+static int verbose;
+
+
+static const char *
+nonnull (const char *s)
+{
+ return s? s :"[none]";
+}
+
+
+static void
+print_import_result (gpgme_import_result_t r)
+{
+ gpgme_import_status_t st;
+
+ printf ("key import results:\n"
+ " considered: %d\n"
+ " no user id: %d\n"
+ " imported: %d\n"
+ " imported_rsa: %d\n"
+ " unchanged: %d\n"
+ " new user ids: %d\n"
+ " new subkeys: %d\n"
+ " new signatures: %d\n"
+ " new revocations: %d\n"
+ " secret read: %d\n"
+ " secret imported: %d\n"
+ " secret unchanged: %d\n"
+ " skipped new keys: %d\n"
+ " not imported: %d\n",
+ r->considered,
+ r->no_user_id,
+ r->imported,
+ r->imported_rsa,
+ r->unchanged,
+ r->new_user_ids,
+ r->new_sub_keys,
+ r->new_signatures,
+ r->new_revocations,
+ r->secret_read,
+ r->secret_imported,
+ r->secret_unchanged,
+ r->skipped_new_keys,
+ r->not_imported);
+
+ for (st=r->imports; st; st = st->next)
+ {
+ printf (" fpr: %s err: %d (%s) status:", nonnull (st->fpr),
+ st->result, gpg_strerror (st->result));
+ if (st->status & GPGME_IMPORT_NEW)
+ fputs (" new", stdout);
+ if (st->status & GPGME_IMPORT_UID)
+ fputs (" uid", stdout);
+ if (st->status & GPGME_IMPORT_SIG)
+ fputs (" sig", stdout);
+ if (st->status & GPGME_IMPORT_SUBKEY)
+ fputs (" subkey", stdout);
+ if (st->status & GPGME_IMPORT_SECRET)
+ fputs (" secret", stdout);
+ putchar ('\n');
+ }
+}
+
+
+static int
+show_usage (int ex)
+{
+ fputs ("usage: " PGM " [options] [USERID]\n\n"
+ "Options:\n"
+ " --verbose run in verbose mode\n"
+ " --local use GPGME_KEYLIST_MODE_LOCAL\n"
+ " --extern use GPGME_KEYLIST_MODE_EXTERN\n"
+ " --sigs use GPGME_KEYLIST_MODE_SIGS\n"
+ " --sig-notations use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n"
+ " --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
+ " --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
+ " --import import all keys\n"
+ , stderr);
+ exit (ex);
+}
+
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ gpgme_error_t err;
+ gpgme_ctx_t ctx;
+ gpgme_keylist_mode_t mode = 0;
+ gpgme_key_t key;
+ gpgme_keylist_result_t result;
+ int import = 0;
+ gpgme_key_t keyarray[100];
+ int keyidx = 0;
+
+ if (argc)
+ { argc--; argv++; }
+
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--"))
+ {
+ argc--; argv++;
+ break;
+ }
+ else if (!strcmp (*argv, "--help"))
+ show_usage (0);
+ else if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--local"))
+ {
+ mode |= GPGME_KEYLIST_MODE_LOCAL;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--extern"))
+ {
+ mode |= GPGME_KEYLIST_MODE_EXTERN;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--sigs"))
+ {
+ mode |= GPGME_KEYLIST_MODE_SIGS;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--sig-notations"))
+ {
+ mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--ephemeral"))
+ {
+ mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--validate"))
+ {
+ mode |= GPGME_KEYLIST_MODE_VALIDATE;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--import"))
+ {
+ import = 1;
+ argc--; argv++;
+ }
+ else if (!strncmp (*argv, "--", 2))
+ show_usage (1);
+
+ }
+
+ if (argc > 1)
+ show_usage (1);
+
+ init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
+ gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+
+ gpgme_set_keylist_mode (ctx, mode);
+
+ err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, 0);
+ fail_if_err (err);
+
+ while (!(err = gpgme_op_keylist_next (ctx, &key)))
+ {
+ gpgme_user_id_t uid;
+ int nuids;
+
+
+ printf ("keyid : %s\n", key->subkeys?nonnull (key->subkeys->keyid):"?");
+ printf ("fpr : %s\n", key->subkeys?nonnull (key->subkeys->fpr):"?");
+ printf ("caps : %s%s%s%s\n",
+ key->can_encrypt? "e":"",
+ key->can_sign? "s":"",
+ key->can_certify? "c":"",
+ key->can_authenticate? "a":"");
+ printf ("flags :%s%s%s%s%s%s\n",
+ key->secret? " secret":"",
+ key->revoked? " revoked":"",
+ key->expired? " expired":"",
+ key->disabled? " disabled":"",
+ key->invalid? " invalid":"",
+ key->is_qualified? " qualifid":"");
+ for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++)
+ {
+ printf ("userid %d: %s\n", nuids, nonnull(uid->uid));
+ printf ("valid %d: %s\n", nuids,
+ uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
+ uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
+ uid->validity == GPGME_VALIDITY_NEVER? "never":
+ uid->validity == GPGME_VALIDITY_MARGINAL? "marginal":
+ uid->validity == GPGME_VALIDITY_FULL? "full":
+ uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]");
+ }
+
+ putchar ('\n');
+
+ if (import)
+ {
+ if (keyidx < DIM (keyarray)-1)
+ keyarray[keyidx++] = key;
+ else
+ {
+ fprintf (stderr, PGM": too many keys in import mode"
+ "- skipping this key\n");
+ gpgme_key_unref (key);
+ }
+ }
+ else
+ gpgme_key_unref (key);
+ }
+ if (gpg_err_code (err) != GPG_ERR_EOF)
+ fail_if_err (err);
+ err = gpgme_op_keylist_end (ctx);
+ fail_if_err (err);
+ keyarray[keyidx] = NULL;
+
+ result = gpgme_op_keylist_result (ctx);
+ if (result->truncated)
+ {
+ fprintf (stderr, PGM ": key listing unexpectedly truncated\n");
+ exit (1);
+ }
+
+ if (import)
+ {
+ gpgme_import_result_t impres;
+
+ err = gpgme_op_import_keys (ctx, keyarray);
+ fail_if_err (err);
+ impres = gpgme_op_import_result (ctx);
+ if (!impres)
+ {
+ fprintf (stderr, PGM ": no import result returned\n");
+ exit (1);
+ }
+ print_import_result (impres);
+ }
+
+ for (keyidx=0; keyarray[keyidx]; keyidx++)
+ gpgme_key_unref (keyarray[keyidx]);
+
+ gpgme_release (ctx);
+ return 0;
+}
gpgme_error_t err;
gpgme_data_t out;
const char *pattern[] = { "Alpha", "Bob", NULL };
+ gpgme_key_t keyarray[3];
init_gpgme (GPGME_PROTOCOL_OpenPGP);
fputs ("End Result.\n", stdout);
gpgme_data_release (out);
+
+ /* Again. Now using a key array. */
+ err = gpgme_data_new (&out);
+ fail_if_err (err);
+
+ err = gpgme_get_key (ctx, "0x68697734" /* Alpha */, keyarray+0, 0);
+ fail_if_err (err);
+ err = gpgme_get_key (ctx, "0xA9E3B0B2" /* Bob */, keyarray+1, 0);
+ fail_if_err (err);
+ keyarray[2] = NULL;
+
+ gpgme_set_armor (ctx, 1);
+ err = gpgme_op_export_keys (ctx, keyarray, 0, out);
+ fail_if_err (err);
+
+ gpgme_key_unref (keyarray[0]);
+ gpgme_key_unref (keyarray[1]);
+
+ fflush (NULL);
+ fputs ("Begin Result:\n", stdout);
+ print_data (out);
+ fputs ("End Result.\n", stdout);
+
+ gpgme_data_release (out);
+
+
gpgme_release (ctx);
return 0;