core: New API gpgme_op_set_uid_flag.
authorWerner Koch <wk@gnupg.org>
Tue, 21 Mar 2017 18:02:20 +0000 (19:02 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 21 Mar 2017 18:03:58 +0000 (19:03 +0100)
* src/gpgme.h.in (gpgme_op_set_uid_flag_start): New.
(gpgme_op_set_uid_flag_start): New.
* src/gpgme.def, src/libgpgme.vers: Add them.
* src/genkey.c (addrevuid_start): Change arg revoke to a flag.
(gpgme_op_revuid_start): Pass GENKEY_EXTRAFLAG_REVOKE for the fomer
revoke parameter.
(gpgme_op_revuid): Ditto.
(set_uid_flag): New.
(gpgme_op_set_uid_flag_start): New.
(gpgme_op_set_uid_flag): New.
* src/engine.h (GENKEY_EXTRAFLAG_SETPRIMARY): new.
* src/engine-gpg.c (gpg_adduid): Implement that flag.

* tests/run-genkey.c (main): New command --set-primary.
--

GnuPG-bug-id: 2931
Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
doc/gpgme.texi
src/engine-gpg.c
src/engine.h
src/genkey.c
src/gpgme.def
src/gpgme.h.in
src/libgpgme.vers
tests/run-genkey.c

diff --git a/NEWS b/NEWS
index 16e1550..367b718 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,10 +10,12 @@ Noteworthy changes in version 1.8.1 (unreleased)
  gpgme_op_createkey          CHANGED: Meaning of 'expire' parameter.
  gpgme_op_createsubkey       CHANGED: Meaning of 'expire' parameter.
  GPGME_CREATE_NOEXPIRE       NEW.
- gpgme_subkey_t              EXTENDED: New field is_de_vs.
+ gpgme_subkey_t              EXTENDED: New field 'is_de_vs'.
  gpgme_op_keylist_from_data_start NEW.
+ gpgme_op_set_uid_flag_start      NEW.
+ gpgme_op_set_uid_flag            NEW.
  GPGME_ENCRYPT_THROW_KEYIDS       NEW.
- gpgme_data_rewind                UN-DEPRECATE
+ gpgme_data_rewind                UN-DEPRECATE.
  cpp: Context::revUid(const Key&, const char*)      NEW.
  cpp: Context::startRevUid(const Key&, const char*) NEW.
  cpp: Context::addUid(const Key&, const char*)      NEW.
index 9846299..fd1f9bc 100644 (file)
@@ -3897,6 +3897,61 @@ be completed by calling @code{gpgme_wait} on the context.
 
 
 @c
+@c  gpgme_op_set_uid_flag
+@c
+@deftypefun gpgme_error_t gpgme_op_set_ui_flag @
+      (@w{gpgme_ctx_t @var{ctx}}, @
+       @w{gpgme_key_t @var{key}}, @
+       @w{const char *@var{userid}}, @
+       @w{cons char * @var{name}}, @
+       @w{cons char * @var{value}});
+
+The function @code{gpgme_op_set_uid_flag} is used to set flags on a
+user ID from the OpenPGP key given by @var{KEY}.  Setting flags on
+user IDs after key creation is a feature of the OpenPGP protocol and
+thus the protocol for the context @var{ctx} must be set to OpenPGP.
+
+@var{key} specifies the key to operate on.  This parameters is required.
+
+@var{userid} is the user ID of the key to be manipulated.  This user ID
+must be given verbatim because the engine does an exact and case
+sensitive match.  Thus the @code{uid} field from the user ID object
+(@code{gpgme_user_id_t}) is to be used.  This is a required parameter.
+
+@var{name} names the flag which is to be changed.  The only currently
+supported flag is:
+
+@table @code
+@item primary
+This sets the primary key flag on the given user ID.  All other
+primary key flag on other user IDs are removed.  @var{value} must be
+given as NULL.  For technical reasons this functions bumps the
+creation timestamp of all affected self-signatures up by one second.
+At least GnuPG version 2.1.20 is required.
+
+@end table
+
+The function returns zero on success, @code{GPG_ERR_NOT_SUPPORTED} if
+the engine does not support the command, or a bunch of other error
+codes.
+
+@end deftypefun
+
+@deftypefun gpgme_error_t gpgme_op_set_uid_flag_start @
+      (@w{gpgme_ctx_t @var{ctx}}, @
+       @w{gpgme_key_t @var{key}}, @
+       @w{const char *@var{userid}}, @
+       @w{cons char * @var{name}}, @
+       @w{cons char * @var{value}});
+
+The function @code{gpgme_op_set_uid_flag_start} initiates a
+@code{gpgme_op_set_uid_flag} operation; see there for details.  It must
+be completed by calling @code{gpgme_wait} on the context.
+@xref{Waiting For Completion}.
+
+@end deftypefun
+
+@c
 @c  gpgme_op_genkey
 @c
 @deftypefun gpgme_error_t gpgme_op_genkey @
index 6024529..6e4b833 100644 (file)
@@ -2222,7 +2222,14 @@ gpg_adduid (engine_gpg_t gpg,
   if (!key || !key->fpr || !userid)
     return gpg_error (GPG_ERR_INV_ARG);
 
-  if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
+  if ((extraflags & GENKEY_EXTRAFLAG_SETPRIMARY))
+    {
+      if (!have_gpg_version (gpg, "2.1.20"))
+        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      else
+        err = add_arg (gpg, "--quick-set-primary-uid");
+    }
+  else if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
     err = add_arg (gpg, "--quick-revuid");
   else
     err = add_arg (gpg, "--quick-adduid");
@@ -2262,7 +2269,7 @@ gpg_genkey (void *engine,
    *  USERID && !KEY          - Create a new keyblock.
    * !USERID &&  KEY          - Add a new subkey to KEY (gpg >= 2.1.14)
    *  USERID &&  KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
-   *
+   *                            or set a flag on a user id.
    */
   if (help_data)
     {
index f456812..1064f5e 100644 (file)
@@ -25,8 +25,9 @@
 #include "gpgme.h"
 
 /* Flags used by the EXTRAFLAGS arg of _gpgme_engine_op_genkey.  */
-#define GENKEY_EXTRAFLAG_ARMOR   1
-#define GENKEY_EXTRAFLAG_REVOKE  2
+#define GENKEY_EXTRAFLAG_ARMOR      1
+#define GENKEY_EXTRAFLAG_REVOKE     2
+#define GENKEY_EXTRAFLAG_SETPRIMARY 4
 
 
 struct engine;
index ea3f1ea..710b58f 100644 (file)
@@ -489,7 +489,7 @@ gpgme_op_createsubkey (gpgme_ctx_t ctx, gpgme_key_t key, const char *algo,
 
 \f
 static gpgme_error_t
-addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke,
+addrevuid_start (gpgme_ctx_t ctx, int synchronous, int extraflags,
                  gpgme_key_t key, const char *userid, unsigned int flags)
 {
   gpgme_error_t err;
@@ -512,7 +512,7 @@ addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke,
   if (err)
     return err;
 
-  opd->uidmode = revoke? 2 : 1;
+  opd->uidmode = extraflags? 2 : 1;
 
   _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
 
@@ -528,7 +528,7 @@ addrevuid_start (gpgme_ctx_t ctx, int synchronous, int revoke,
                                   userid, NULL, 0, 0,
                                   key, flags,
                                   NULL,
-                                 revoke? GENKEY_EXTRAFLAG_REVOKE : 0,
+                                 extraflags,
                                   NULL, NULL);
 
 }
@@ -584,7 +584,7 @@ gpgme_op_revuid_start (gpgme_ctx_t ctx,
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
 
-  err = addrevuid_start (ctx, 0, 1, key, userid, flags);
+  err = addrevuid_start (ctx, 0, GENKEY_EXTRAFLAG_REVOKE, key, userid, flags);
   return TRACE_ERR (err);
 }
 
@@ -601,8 +601,60 @@ gpgme_op_revuid (gpgme_ctx_t ctx,
   if (!ctx)
     return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
 
-  err = addrevuid_start (ctx, 1, 1, key, userid, flags);
+  err = addrevuid_start (ctx, 1, GENKEY_EXTRAFLAG_REVOKE, key, userid, flags);
   if (!err)
     err = _gpgme_wait_one (ctx);
   return TRACE_ERR (err);
 }
+
+
+/* Set a flag on the USERID of KEY.  The only supported flag right now
+ * is "primary" to mark the primary key.  */
+static gpg_error_t
+set_uid_flag (gpgme_ctx_t ctx, int synchronous,
+              gpgme_key_t key, const char *userid,
+              const char *name, const char *value)
+{
+  gpgme_error_t err;
+
+  TRACE_BEG4 (DEBUG_CTX, "gpgme_op_set_uid_flag", ctx,
+             "%d uid='%s' '%s'='%s'", synchronous, userid, name, value);
+
+  if (!ctx || !name || !key || !userid)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG));
+
+  if (!strcmp (name, "primary"))
+    {
+      if (value)
+        err = gpg_error (GPG_ERR_INV_ARG);
+      else
+        err = addrevuid_start (ctx, synchronous,
+                               GENKEY_EXTRAFLAG_SETPRIMARY, key, userid, 0);
+    }
+  else
+    return err = gpg_error (GPG_ERR_UNKNOWN_NAME);
+
+  if (synchronous && !err)
+    err = _gpgme_wait_one (ctx);
+  return TRACE_ERR (err);
+}
+
+
+/* See set_uid_flag. */
+gpgme_error_t
+gpgme_op_set_uid_flag_start (gpgme_ctx_t ctx,
+                             gpgme_key_t key, const char *userid,
+                             const char *name, const char *value)
+{
+  return set_uid_flag (ctx, 0, key, userid, name, value);
+}
+
+
+/* See set_uid_flag.  Thsi is the synchronous variant.  */
+gpgme_error_t
+gpgme_op_set_uid_flag (gpgme_ctx_t ctx,
+                       gpgme_key_t key, const char *userid,
+                       const char *name, const char *value)
+{
+  return set_uid_flag (ctx, 1, key, userid, name, value);
+}
index ddd57d3..9faffb8 100644 (file)
@@ -256,5 +256,8 @@ EXPORTS
 
     gpgme_op_keylist_from_data_start      @192
 
+    gpgme_op_set_uid_flag_start           @193
+    gpgme_op_set_uid_flag                 @194
+
 ; END
 
index 16191eb..e9ee6e2 100644 (file)
@@ -1726,6 +1726,13 @@ gpgme_error_t gpgme_op_revuid       (gpgme_ctx_t ctx,
                                      gpgme_key_t key, const char *userid,
                                      unsigned int reserved);
 
+/* Set a flag on the USERID of KEY.  See the manual for supported flags.  */
+gpgme_error_t gpgme_op_set_uid_flag_start (gpgme_ctx_t ctx,
+                                           gpgme_key_t key, const char *userid,
+                                           const char *name, const char *value);
+gpgme_error_t gpgme_op_set_uid_flag       (gpgme_ctx_t ctx,
+                                           gpgme_key_t key, const char *userid,
+                                           const char *name, const char *value);
 
 
 /* Retrieve a pointer to the result of a genkey, createkey, or
index 9344a75..037a6ae 100644 (file)
@@ -126,6 +126,9 @@ GPGME_1.1 {
 
     gpgme_op_query_swdb;
     gpgme_op_query_swdb_result;
+
+    gpgme_op_set_uid_flag_start;
+    gpgme_op_set_uid_flag;
 };
 
 
index c5abc42..91edb22 100644 (file)
@@ -204,10 +204,12 @@ show_usage (int ex)
          "   for addkey: FPR    [ALGO [USAGE [EXPIRESECONDS]]]\n"
          "   for adduid: FPR    USERID\n"
          "   for revuid: FPR    USERID\n"
+         "   for set-primary: FPR    USERID\n"
          "Options:\n"
          "  --addkey         add a subkey to the key with FPR\n"
          "  --adduid         add a user id to the key with FPR\n"
-         "  --revuid         Revoke a user id from the key with FPR\n"
+         "  --revuid         revoke a user id from the key with FPR\n"
+         "  --set-primary    set the primary key flag on USERID\n"
          "  --verbose        run in verbose mode\n"
          "  --status         print status lines from the backend\n"
          "  --progress       print progress info\n"
@@ -234,6 +236,7 @@ main (int argc, char **argv)
   int addkey = 0;
   int adduid = 0;
   int revuid = 0;
+  int setpri = 0;
   const char *userid;
   const char *algo = NULL;
   const char *newuserid = NULL;
@@ -259,6 +262,7 @@ main (int argc, char **argv)
           addkey = 1;
           adduid = 0;
           revuid = 0;
+          setpri = 0;
           argc--; argv++;
         }
       else if (!strcmp (*argv, "--adduid"))
@@ -266,6 +270,7 @@ main (int argc, char **argv)
           addkey = 0;
           adduid = 1;
           revuid = 0;
+          setpri = 0;
           argc--; argv++;
         }
       else if (!strcmp (*argv, "--revuid"))
@@ -273,6 +278,15 @@ main (int argc, char **argv)
           addkey = 0;
           adduid = 0;
           revuid = 1;
+          setpri = 0;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--set-primary"))
+        {
+          addkey = 0;
+          adduid = 0;
+          revuid = 0;
+          setpri = 1;
           argc--; argv++;
         }
       else if (!strcmp (*argv, "--verbose"))
@@ -319,7 +333,7 @@ main (int argc, char **argv)
         show_usage (1);
     }
 
-  if (adduid || revuid)
+  if (adduid || revuid || setpri)
     {
       if (argc != 2)
         show_usage (1);
@@ -358,7 +372,7 @@ main (int argc, char **argv)
       gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
     }
 
-  if (addkey || adduid || revuid)
+  if (addkey || adduid || revuid || setpri)
     {
       gpgme_key_t akey;
 
@@ -400,6 +414,16 @@ main (int argc, char **argv)
               exit (1);
             }
         }
+      else if (setpri)
+        {
+          err = gpgme_op_set_uid_flag (ctx, akey, newuserid, "primary", NULL);
+          if (err)
+            {
+              fprintf (stderr, PGM ": gpgme_op_set_uid_flag failed: %s\n",
+                       gpg_strerror (err));
+              exit (1);
+            }
+        }
       gpgme_key_unref (akey);
     }
   else
@@ -413,26 +437,29 @@ main (int argc, char **argv)
         }
     }
 
-  result = gpgme_op_genkey_result (ctx);
-  if (!result)
+  if (!setpri)
     {
-      fprintf (stderr, PGM": gpgme_op_genkey_result returned NULL\n");
-      exit (1);
-    }
+      result = gpgme_op_genkey_result (ctx);
+      if (!result)
+        {
+          fprintf (stderr, PGM": gpgme_op_genkey_result returned NULL\n");
+          exit (1);
+        }
 
-  printf ("Generated key: %s (%s)\n",
-          result->fpr ? result->fpr : "none",
-         result->primary ? (result->sub ? "primary, sub" : "primary")
-          /**/           : (result->sub ? "sub" : "none"));
-
-  if (result->fpr && strlen (result->fpr) < 40)
-    fprintf (stderr, PGM": generated key has unexpected fingerprint\n");
-  if (!result->primary)
-    fprintf (stderr, PGM": primary key was not generated\n");
-  if (!result->sub)
-    fprintf (stderr, PGM": sub key was not generated\n");
-  if (!result->uid)
-    fprintf (stderr, PGM": uid was not generated\n");
+      printf ("Generated key: %s (%s)\n",
+              result->fpr ? result->fpr : "none",
+              result->primary ? (result->sub ? "primary, sub" : "primary")
+              /**/            : (result->sub ? "sub" : "none"));
+
+      if (result->fpr && strlen (result->fpr) < 40)
+        fprintf (stderr, PGM": generated key has unexpected fingerprint\n");
+      if (!result->primary)
+        fprintf (stderr, PGM": primary key was not generated\n");
+      if (!result->sub)
+        fprintf (stderr, PGM": sub key was not generated\n");
+      if (!result->uid)
+        fprintf (stderr, PGM": uid was not generated\n");
+    }
 
   gpgme_release (ctx);
   return 0;