Add new functions to import and export keys specified by gpgme_key_t.
authorWerner Koch <wk@gnupg.org>
Tue, 16 Jun 2009 11:42:21 +0000 (11:42 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 16 Jun 2009 11:42:21 +0000 (11:42 +0000)
Allow  exporting keys to a keyserver.

22 files changed:
NEWS
TODO
assuan/ChangeLog
assuan/assuan-pipe-connect.c
doc/ChangeLog
doc/gpgme.texi
src/ChangeLog
src/engine-backend.h
src/engine-gpg.c
src/engine-gpgsm.c
src/engine.c
src/engine.h
src/export.c
src/gpgme.def
src/gpgme.h.in
src/import.c
src/libgpgme.vers
tests/ChangeLog
tests/gpg/Makefile.am
tests/gpg/pgp-export.c [new file with mode: 0644]
tests/gpg/pgp-keylist.c [new file with mode: 0644]
tests/gpg/t-export.c

diff --git a/NEWS b/NEWS
index 8629d31..232ff53 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-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
@@ -11,7 +11,6 @@ Noteworthy changes in version 1.1.9
  * 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.
@@ -22,12 +21,23 @@ Noteworthy changes in version 1.1.9
  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.
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
diff --git a/TODO b/TODO
index 9aeeb26..d84b295 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,4 +1,4 @@
-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
@@ -24,7 +24,7 @@ Hey Emacs, this is -*- outline -*- mode!
    (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
@@ -68,9 +68,15 @@ Hey Emacs, this is -*- outline -*- mode!
    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
@@ -82,6 +88,7 @@ Hey Emacs, this is -*- outline -*- mode!
 *** 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
@@ -110,6 +117,11 @@ Hey Emacs, this is -*- outline -*- mode!
    (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
index 8dd2ebb..617cb00 100644 (file)
@@ -1,3 +1,8 @@
+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.
index 7fdfe74..fcede19 100644 (file)
@@ -51,7 +51,7 @@ struct spawn_fd_item_s
 
 
 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
 
@@ -659,7 +659,7 @@ pipe_connect_gpgme (assuan_context_t *ctx,
   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));
index e1bb4a5..5138a57 100644 (file)
@@ -1,3 +1,8 @@
+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.
index 871575a..a6f15d1 100644 (file)
@@ -3318,7 +3318,25 @@ operation is started on the context.
 @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
@@ -3329,7 +3347,7 @@ If @var{pattern} is @code{NULL}, all available keys are returned.
 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
@@ -3337,7 +3355,7 @@ 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}.
@@ -3347,7 +3365,7 @@ operation could be started successfully, and @code{GPG_ERR_INV_VALUE}
 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
@@ -3359,7 +3377,7 @@ are returned.  Otherwise, @var{pattern} is a @code{NULL} terminated
 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
@@ -3367,7 +3385,7 @@ 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}.
@@ -3378,11 +3396,50 @@ if @var{keydata} is not a valid empty data buffer.
 @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}.
@@ -3409,6 +3466,44 @@ import could be started successfully, @code{GPG_ERR_INV_VALUE} if
 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
index 35622ee..dc1e116 100644 (file)
@@ -1,3 +1,34 @@
+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
index d656d9d..1fe600d 100644 (file)
@@ -77,14 +77,15 @@ struct engine_ops
                                 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[],
index eec3fa6..3c06edf 100644 (file)
@@ -678,7 +678,7 @@ command_handler (void *opaque, int fd)
 
 
 /* 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.  */
@@ -1704,23 +1704,42 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
 
 
 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);
 
@@ -1732,22 +1751,13 @@ gpg_export (void *engine, const char *pattern, unsigned int reserved,
 
 
 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)
     {
@@ -1795,16 +1805,40 @@ gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
 
 
 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);
index 2d92732..71ef221 100644 (file)
@@ -1379,15 +1379,18 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
 
 
 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 = "";
@@ -1414,7 +1417,7 @@ gpgsm_export (void *engine, const char *pattern, unsigned int reserved,
 
 
 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;
@@ -1424,9 +1427,12 @@ gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved,
   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;
@@ -1534,7 +1540,7 @@ gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
 
 
 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;
@@ -1542,13 +1548,23 @@ gpgsm_import (void *engine, gpgme_data_t keydata)
   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;
index 87d3939..c8ff012 100644 (file)
@@ -620,7 +620,7 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
 
 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)
@@ -629,7 +629,7 @@ _gpgme_engine_op_export (engine_t engine, const char *pattern,
   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);
 }
 
@@ -667,7 +667,8 @@ _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
 
 
 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);
@@ -675,7 +676,7 @@ _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
   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);
 }
 
 
index a043b3e..ca746c8 100644 (file)
@@ -93,11 +93,11 @@ gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
                                             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,
@@ -105,7 +105,8 @@ 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,
index 079a7e0..1e29439 100644 (file)
@@ -22,6 +22,8 @@
 #if HAVE_CONFIG_H
 #include <config.h>
 #endif
+#include <stdlib.h>
+#include <string.h>
 
 #include "gpgme.h"
 #include "context.h"
@@ -37,12 +39,24 @@ export_status_handler (void *priv, gpgme_status_code_t code, char *args)
 
 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)
@@ -50,26 +64,26 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
 
   _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;
@@ -78,12 +92,23 @@ gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved,
 \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)
@@ -91,27 +116,108 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
 
   _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;
 }
+
index 9bc95d0..ac0fe9a 100644 (file)
@@ -180,5 +180,10 @@ EXPORTS
     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
 
index 8e224a4..ff9bba0 100644 (file)
@@ -329,6 +329,12 @@ gpgme_protocol_t;
 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 
 #define GPGME_AUDITLOG_WITH_HELP 128
@@ -1497,22 +1503,39 @@ gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata);
 gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
                                   int *nr) _GPGME_DEPRECATED;
 
+/* 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
index ad6b776..8212a25 100644 (file)
@@ -238,7 +238,7 @@ _gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata)
 
   _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);
 }
 
 
@@ -260,6 +260,84 @@ gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata)
 }
 
 
+\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)
 {
index 44f6176..41fa1be 100644 (file)
@@ -59,6 +59,11 @@ GPGME_1.1 {
 
     gpgme_result_ref;
     gpgme_result_unref;
+
+    gpgme_op_import_keys;
+    gpgme_op_import_keys_start;
+    gpgme_op_export_keys;
+    gpgme_op_export_keys_start;
 };
 
 
index a727a89..c9ab133 100644 (file)
@@ -1,3 +1,7 @@
+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
@@ -16,7 +20,8 @@
 
        * 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>
 
index 5da0bbb..fdb023c 100644 (file)
@@ -50,7 +50,8 @@ LDADD = ../../src/libgpgme.la
 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
diff --git a/tests/gpg/pgp-export.c b/tests/gpg/pgp-export.c
new file mode 100644 (file)
index 0000000..9911c18
--- /dev/null
@@ -0,0 +1,168 @@
+/* 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;
+}
diff --git a/tests/gpg/pgp-keylist.c b/tests/gpg/pgp-keylist.c
new file mode 100644 (file)
index 0000000..2645f48
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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;
+}
index f469843..85cff23 100644 (file)
@@ -42,6 +42,7 @@ main (int argc, char **argv)
   gpgme_error_t err;
   gpgme_data_t  out;
   const char *pattern[] = { "Alpha", "Bob", NULL };
+  gpgme_key_t keyarray[3];
 
   init_gpgme (GPGME_PROTOCOL_OpenPGP);
 
@@ -61,6 +62,32 @@ main (int argc, char **argv)
   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;