[git] GPGME - branch, master, updated. gpgme-1.7.1-17-gaad94cb

by Werner Koch cvs at cvs.gnupg.org
Thu Nov 3 17:35:12 CET 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  aad94cb7c313d4501bed748f48830cbb93c67e20 (commit)
      from  34a4e8017be452e8ead6b9c2da84be1ec7929cae (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit aad94cb7c313d4501bed748f48830cbb93c67e20
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Nov 3 16:29:45 2016 +0100

    core: Add gpgme_op_query_swdb and helper.
    
    * src/gpgme.h.in (gpgme_query_swdb_result_t): New.
    (gpgme_op_query_swdb): New.
    (gpgme_op_query_swdb_result): New.
    * src/libgpgme.vers, src/gpgme.def: Add the two new functions.
    * src/queryswdb.c: New.
    * src/Makefile.am (main_sources): Add new file.
    * src/context.h (OPDATA_QUERY_SWDB): New.
    * src/engine-backend.h (struct engine_ops): Add field 'query_swdb'.
    Adjust all initializer.
    * src/engine.c (_gpgme_engine_op_query_swdb): New.
    * src/engine-gpgconf.c (parse_swdb_line): New.
    (gpgconf_query_swdb): New.
    (_gpgme_engine_ops_gpgconf): Register that function.
    
    * src/util.h (GPG_ERR_TOO_OLD): Define for older libgpg-error.
    (GPG_ERR_ENGINE_TOO_OLD): Ditto.
    
    * tests/run-swdb.c: New.
    * tests/Makefile.am (noinst_PROGRAMS): Add new debug tool.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index 0274f9c..e43aa30 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ Noteworthy changes in version 1.7.2 (unreleased)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gpgme_set_sender                NEW.
  gpgme_get_sender                NEW.
+ gpgme_op_query_swdb             NEW.
+ gpgme_op_query_swdb_result      NEW.
+ gpgme_query_swdb_result_t       NEW.
  qt: DN                          NEW.
  qt: DN::Attribute               NEW.
 
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index 9fae9aa..a70418d 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -237,7 +237,9 @@ Encrypt
 
 Miscellaneous
 
-* Running other Programs::        Running other Programs
+* Running other Programs::        Running other Programs.
+* Using the Assuan protocol::     Using the Assuan protocol.
+* Checking for updates::          How to check for software updates.
 
 Run Control
 
@@ -5561,6 +5563,7 @@ Here are some support functions which are sometimes useful.
 @menu
 * Running other Programs::      Running other Programs
 * Using the Assuan protocol::   Using the Assuan protocol
+* Checking for updates::        How to check for software updates
 @end menu
 
 
@@ -5692,6 +5695,142 @@ Synchronous variant.
 @end deftypefun
 
 
+ at node Checking for updates
+ at subsection How to check for software updates
+
+The GnuPG Project operates a server to query the current versions of
+software packages related to GnuPG.  GPGME can be used to
+access this online database and check whether a new version of a
+software package is available.
+
+ at deftp {Data type} {gpgme_query_swdb_result_t}
+This is a pointer to a structure used to store the result of a
+ at code{gpgme_op_query_swdb} operation.  After success full call to that
+function, you can retrieve the pointer to the result with
+ at code{gpgme_op_query_swdb_result}.  The structure contains the
+following member:
+
+ at table @code
+ at item name
+This is the name of the package.
+
+ at item iversion
+The currently installed version or an empty string.  This value is
+either a copy of the argument given to @code{gpgme_op_query_swdb} or
+the version of the installed software as figured out by GPGME or GnuPG.
+
+ at item created
+This gives the date the file with the list of version numbers has
+originally be created by the GnuPG project.
+
+ at item retrieved
+This gives the date the file was downloaded.
+
+ at item warning
+If this flag is set either an error has occurred or some of the
+information in this structure are not properly set.  For example if
+the version number of the installed software could not be figured out,
+the @code{update} flag may not reflect a required update status.
+
+ at item update
+If this flag is set an update of the software is available.
+
+ at item urgent
+If this flag is set an available update is important.
+
+ at item noinfo
+If this flag is set, no valid information could be retrieved.
+
+ at item unknown
+If this flag is set the given @code{name} is not known.
+
+ at item tooold
+If this flag is set the available information is not fresh enough.
+
+ at item error
+If this flag is set some other error has occured.
+
+ at item version
+The version string of the latest released version.
+
+ at item reldate
+The release date of the latest released version.
+
+ at end table
+ at end deftp
+
+ at deftypefun gpgme_error_t gpgme_op_query_swdb @
+            (@w{gpgme_ctx_t @var{ctx}},       @
+             @w{const char *@var{name}},      @
+             @w{const char *@var{iversion}},  @
+             @w{gpgme_data_t @var{reserved}})
+
+Query the software version database for software package @var{name}
+and check against the installed version given by @var{iversion}.  If
+ at var{iversion} is given as @code{NULL} a check is only done if GPGME
+can figure out the version by itself (for example when using
+"gpgme" or "gnupg").  If @code{NULL} is used for @var{name} the
+current gpgme version is checked.  @var{reserved} must be set to 0.
+
+ at end deftypefun
+
+ at deftypefun gpgme_query_swdb_result_t gpgme_op_query_swdb_result @
+            (@w{gpgme_ctx_t @var{ctx}})
+
+The function @code{gpgme_op_query_swdb_result} returns a
+ at code{gpgme_query_swdb_result_t} pointer to a structure holding the
+result of a @code{gpgme_op_query_swdb} operation.  The pointer is only
+valid if the last operation on the context was a sucessful call to
+ at code{gpgme_op_query_swdb}.  If that call failed, the result might
+be a @code{NULL} pointer.  The returned pointer is only valid until
+the next operation is started on the context @var{ctx}.
+ at end deftypefun
+
+ at noindent
+Here is an example on how to check whether GnuPG is current:
+
+ at example
+#include <gpgme.h>
+
+int
+main (void)
+@{
+  gpg_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_query_swdb_result_t result;
+
+  gpgme_check_version (NULL);
+  err = gpgme_new (&ctx);
+  if (err)
+    fprintf (stderr, "error creating context: %s\n", gpg_strerror (err));
+  else
+    @{
+      gpgme_set_protocol (ctx, GPGME_PROTOCOL_GPGCONF);
+
+      err = gpgme_op_query_swdb (ctx, "gnupg", NULL, 0);
+      if (err)
+        fprintf (stderr, "error querying swdb: %s\n", gpg_strerror (err));
+      else
+        @{
+          result = gpgme_op_query_swdb_result (ctx);
+          if (!result)
+            fprintf (stderr, "error querying swdb\n");
+          if (!result->warning && !result->update)
+            printf ("GnuPG version %s is current\n",
+                    result->iversion);
+          else if (!result->warning && result->update)
+            printf ("GnuPG version %s can be updated to %s\n",
+                    result->iversion, result->version);
+          else
+            fprintf (stderr, "error finding the update status\n");
+        @}
+      gpgme_release (ctx);
+    @}
+  return 0;
+@}
+ at end example
+
+
 @node Run Control
 @section Run Control
 @cindex run control
diff --git a/src/Makefile.am b/src/Makefile.am
index f166f3b..eddd192 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -91,7 +91,7 @@ main_sources =								\
 	$(uiserver_components)						\
 	engine-g13.c vfs-mount.c vfs-create.c			        \
 	engine-spawn.c 	                                                \
-	gpgconf.c							\
+	gpgconf.c queryswdb.c						\
 	sema.h priv-io.h $(system_components) sys-util.h dirinfo.c	\
 	debug.c debug.h gpgme.c version.c error.c
 
diff --git a/src/context.h b/src/context.h
index f6c1ad1..00e2e77 100644
--- a/src/context.h
+++ b/src/context.h
@@ -38,7 +38,8 @@ typedef enum
     OPDATA_DECRYPT, OPDATA_SIGN, OPDATA_ENCRYPT, OPDATA_PASSPHRASE,
     OPDATA_IMPORT, OPDATA_GENKEY, OPDATA_KEYLIST, OPDATA_EDIT,
     OPDATA_VERIFY, OPDATA_TRUSTLIST, OPDATA_ASSUAN, OPDATA_VFS_MOUNT,
-    OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY
+    OPDATA_PASSWD, OPDATA_EXPORT, OPDATA_KEYSIGN, OPDATA_TOFU_POLICY,
+    OPDATA_QUERY_SWDB
   } ctx_op_data_id_t;
 
 
diff --git a/src/engine-assuan.c b/src/engine-assuan.c
index 65924eb..4c7fe28 100644
--- a/src/engine-assuan.c
+++ b/src/engine-assuan.c
@@ -796,6 +796,7 @@ struct engine_ops _gpgme_engine_ops_assuan =
     llass_transact,     /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     llass_set_io_cbs,
     llass_io_event,
     llass_cancel,
diff --git a/src/engine-backend.h b/src/engine-backend.h
index e02c715..a8b1ac6 100644
--- a/src/engine-backend.h
+++ b/src/engine-backend.h
@@ -127,6 +127,10 @@ struct engine_ops
   gpgme_error_t  (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p);
   gpgme_error_t  (*conf_save) (void *engine, gpgme_conf_comp_t conf);
 
+  gpgme_error_t  (*query_swdb) (void *engine,
+                                const char *name, const char *iversion,
+                                gpgme_query_swdb_result_t result);
+
   void (*set_io_cbs) (void *engine, gpgme_io_cbs_t io_cbs);
   void (*io_event) (void *engine, gpgme_event_io_t type, void *type_data);
 
diff --git a/src/engine-g13.c b/src/engine-g13.c
index d34db82..972c3a8 100644
--- a/src/engine-g13.c
+++ b/src/engine-g13.c
@@ -811,6 +811,7 @@ struct engine_ops _gpgme_engine_ops_g13 =
     g13_transact,
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     g13_set_io_cbs,
     g13_io_event,
     g13_cancel,
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index cb52dea..7725a00 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -2969,6 +2969,7 @@ struct engine_ops _gpgme_engine_ops_gpg =
     NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     gpg_set_io_cbs,
     gpg_io_event,
     gpg_cancel,
diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
index 271a4dd..25c798e 100644
--- a/src/engine-gpgconf.c
+++ b/src/engine-gpgconf.c
@@ -47,6 +47,7 @@
 
 #include "engine-backend.h"
 
+
 

 struct engine_gpgconf
 {
@@ -941,6 +942,217 @@ gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
 }
 
 
+/* Parse a line received from gpgconf --query-swdb.  This function may
+ * modify LINE.  The result is stored at RESUL.  */
+static gpg_error_t
+parse_swdb_line (char *line, gpgme_query_swdb_result_t result)
+{
+  char *field[9];
+  int fields = 0;
+  gpg_err_code_t ec;
+
+  while (line && fields < DIM (field))
+    {
+      field[fields++] = line;
+      line = strchr (line, ':');
+      if (line)
+	*line++ = 0;
+    }
+  /* We require that all fields exists - gpgme emits all these fields
+   * even on error.  They might be empty, though. */
+  if (fields < 9)
+    return gpg_error (GPG_ERR_INV_ENGINE);
+
+  free (result->name);
+  result->name = strdup (field[0]);
+  if (!result->name)
+    return gpg_error_from_syserror ();
+
+  free (result->iversion);
+  result->iversion = strdup (field[1]);
+  if (!result->iversion)
+    return gpg_error_from_syserror ();
+
+  result->urgent = (strtol (field[3], NULL, 10) > 0);
+
+  ec = gpg_err_code (strtoul (field[4], NULL, 10));
+
+  result->created  = _gpgme_parse_timestamp (field[5], NULL);
+  result->retrieved= _gpgme_parse_timestamp (field[6], NULL);
+
+  free (result->version);
+  result->version  = strdup (field[7]);
+  if (!result->version)
+    return gpg_error_from_syserror ();
+
+  result->reldate  = _gpgme_parse_timestamp (field[8], NULL);
+
+  /* Set other flags.  */
+  result->warning = !!ec;
+  result->update = 0;
+  result->noinfo = 0;
+  result->unknown = 0;
+  result->tooold = 0;
+  result->error = 0;
+
+  switch (*field[2])
+    {
+    case '-': result->warning = 1; break;
+    case '?': result->unknown = result->warning = 1; break;
+    case 'u': result->update = 1; break;
+    case 'c': break;
+    case 'n': break;
+    default:
+      result->warning = 1;
+      if (!ec)
+        ec = GPG_ERR_INV_ENGINE;
+      break;
+    }
+
+  if (ec == GPG_ERR_TOO_OLD)
+    result->tooold = 1;
+  else if (ec == GPG_ERR_ENOENT)
+    result->noinfo = 1;
+  else if (ec)
+    result->error = 1;
+
+
+  return 0;
+}
+
+
+static gpgme_error_t
+gpgconf_query_swdb (void *engine,
+                    const char *name, const char *iversion,
+                    gpgme_query_swdb_result_t result)
+{
+  struct engine_gpgconf *gpgconf = engine;
+  gpgme_error_t err = 0;
+  char *linebuf;
+  size_t linebufsize;
+  int linelen;
+  char *argv[7];
+  int argc = 0;
+  int rp[2];
+  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
+				   {-1, -1} };
+  int status;
+  int nread;
+  char *mark = NULL;
+
+  if (!have_gpgconf_version (gpgconf, "2.1.16"))
+    return gpg_error (GPG_ERR_ENGINE_TOO_OLD);
+
+  /* _gpgme_engine_new guarantees that this is not NULL.  */
+  argv[argc++] = gpgconf->file_name;
+
+  if (gpgconf->home_dir)
+    {
+      argv[argc++] = (char*)"--homedir";
+      argv[argc++] = gpgconf->home_dir;
+    }
+
+  argv[argc++] = (char*)"--query-swdb";
+  argv[argc++] = (char*)name;
+  argv[argc++] = (char*)iversion;
+  argv[argc] = NULL;
+  assert (argc < DIM (argv));
+
+  if (_gpgme_io_pipe (rp, 1) < 0)
+    return gpg_error_from_syserror ();
+
+  cfd[0].fd = rp[1];
+
+  status = _gpgme_io_spawn (gpgconf->file_name, argv,
+                            IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
+  if (status < 0)
+    {
+      _gpgme_io_close (rp[0]);
+      _gpgme_io_close (rp[1]);
+      return gpg_error_from_syserror ();
+    }
+
+  linebufsize = 2048; /* Same as used by gpgconf.  */
+  linebuf = malloc (linebufsize);
+  if (!linebuf)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  linelen = 0;
+
+  while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
+                                  linebufsize - linelen - 1)))
+    {
+      char *line;
+      const char *lastmark = NULL;
+      size_t nused;
+
+      if (nread < 0)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+
+      linelen += nread;
+      linebuf[linelen] = '\0';
+
+      for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
+        {
+          lastmark = mark;
+          if (mark > line && mark[-1] == '\r')
+            mark[-1] = '\0';
+          else
+            mark[0] = '\0';
+
+          /* Got a full line.  Due to the CR removal code (which
+             occurs only on Windows) we might be one-off and thus
+             would see empty lines.  */
+          if (*line)
+            {
+              err = parse_swdb_line (line, result);
+              goto leave; /* Ready.  */
+            }
+          else /* empty line.  */
+            err = 0;
+        }
+
+      nused = lastmark? (lastmark + 1 - linebuf) : 0;
+      memmove (linebuf, linebuf + nused, linelen - nused);
+      linelen -= nused;
+
+      if (!(linelen < linebufsize - 1))
+        {
+          char *newlinebuf;
+
+          if (linelen <  8 * 1024 - 1)
+            linebufsize = 8 * 1024;
+          else if (linelen < 64 * 1024 - 1)
+            linebufsize = 64 * 1024;
+          else
+            {
+              /* We reached our limit - give up.  */
+              err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+              goto leave;
+            }
+
+          newlinebuf = realloc (linebuf, linebufsize);
+          if (!newlinebuf)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          linebuf = newlinebuf;
+        }
+    }
+
+ leave:
+  free (linebuf);
+  _gpgme_io_close (rp[0]);
+  return err;
+}
+
+
 static void
 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
 {
@@ -998,6 +1210,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
     NULL,               /* opassuan_transact */
     gpgconf_conf_load,
     gpgconf_conf_save,
+    gpgconf_query_swdb,
     gpgconf_set_io_cbs,
     NULL,		/* io_event */
     NULL,		/* cancel */
diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c
index 0ce4a6d..a815cf0 100644
--- a/src/engine-gpgsm.c
+++ b/src/engine-gpgsm.c
@@ -2101,6 +2101,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
     NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     gpgsm_set_io_cbs,
     gpgsm_io_event,
     gpgsm_cancel,
diff --git a/src/engine-spawn.c b/src/engine-spawn.c
index df90cb2..d2c7dd6 100644
--- a/src/engine-spawn.c
+++ b/src/engine-spawn.c
@@ -469,6 +469,7 @@ struct engine_ops _gpgme_engine_ops_spawn =
     NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     engspawn_set_io_cbs,
     engspawn_io_event,	/* io_event */
     engspawn_cancel,	/* cancel */
diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c
index 76fa4d7..47b7dc3 100644
--- a/src/engine-uiserver.c
+++ b/src/engine-uiserver.c
@@ -1393,6 +1393,7 @@ struct engine_ops _gpgme_engine_ops_uiserver =
     NULL,               /* opassuan_transact */
     NULL,		/* conf_load */
     NULL,		/* conf_save */
+    NULL,               /* query_swdb */
     uiserver_set_io_cbs,
     uiserver_io_event,
     uiserver_cancel,
diff --git a/src/engine.c b/src/engine.c
index f5dfe51..4e513b6 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -980,6 +980,21 @@ _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
 }
 
 
+gpgme_error_t
+_gpgme_engine_op_query_swdb (engine_t engine,
+                             const char *name, const char *iversion,
+                             gpgme_query_swdb_result_t result)
+{
+  if (!engine)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (!engine->ops->query_swdb)
+    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+  return (*engine->ops->query_swdb) (engine->engine, name, iversion, result);
+}
+
+
 void
 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
 {
diff --git a/src/engine.h b/src/engine.h
index 2999ab6..15b0b5d 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -173,6 +173,12 @@ gpgme_error_t _gpgme_engine_op_conf_load (engine_t engine,
 gpgme_error_t _gpgme_engine_op_conf_save (engine_t engine,
 					  gpgme_conf_comp_t conf);
 
+gpgme_error_t _gpgme_engine_op_query_swdb (engine_t engine,
+                                           const char *name,
+                                           const char *iversion,
+                                           gpgme_query_swdb_result_t result);
+
+
 void _gpgme_engine_set_io_cbs (engine_t engine,
 			       gpgme_io_cbs_t io_cbs);
 void _gpgme_engine_io_event (engine_t engine,
diff --git a/src/gpgconf.c b/src/gpgconf.c
index 6591452..b1b84a6 100644
--- a/src/gpgconf.c
+++ b/src/gpgconf.c
@@ -65,7 +65,7 @@ gpgme_conf_release (gpgme_conf_comp_t conf)
 }
 
 
-/* Public function to release load a configuration list.  No
+/* Public function to load a configuration list.  No
    asynchronous interface for now.  */
 gpgme_error_t
 gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p)
@@ -108,5 +108,3 @@ gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp)
   ctx->protocol = proto;
   return err;
 }
-
-
diff --git a/src/gpgme.def b/src/gpgme.def
index d633df5..2f6837d 100644
--- a/src/gpgme.def
+++ b/src/gpgme.def
@@ -249,5 +249,8 @@ EXPORTS
     gpgme_set_sender                      @187
     gpgme_get_sender                      @188
 
+    gpgme_op_query_swdb                   @189
+    gpgme_op_query_swdb_result            @190
+
 ; END
 
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 94ef51d..4f470a0 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -2418,6 +2418,67 @@ gpgme_error_t gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p);
 gpgme_error_t gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp);
 
 
+/* Information about software versions.  */
+typedef struct _gpgme_op_query_swdb_result
+{
+  /* RFU */
+  struct _gpgme_op_query_swdb_result *next;
+
+  /* The name of the package (e.g. "gpgme", "gnupg") */
+  char *name;
+
+  /* The version number of the installed version.  */
+  char *iversion;
+
+  /* The time the online info was created.  */
+  unsigned long created;
+
+  /* The time the online info was retrieved.  */
+  unsigned long retrieved;
+
+  /* This bit is set if an error occured or some of the information
+   * in this structure may not be set.  */
+  unsigned int warning : 1;
+
+  /* An update is available.  */
+  unsigned int update : 1;
+
+  /* The update is important.  */
+  unsigned int urgent : 1;
+
+  /* No information at all available.  */
+  unsigned int noinfo : 1;
+
+  /* The package name is not known. */
+  unsigned int unknown : 1;
+
+  /* The information here is too old.  */
+  unsigned int tooold : 1;
+
+  /* Other error.  */
+  unsigned int error : 1;
+
+  unsigned int _reserved : 25;
+
+  /* The version number of the latest released version.  */
+  char *version;
+
+  /* The release date of that version.  */
+  unsigned long reldate;
+
+} *gpgme_query_swdb_result_t;
+
+
+/* Run the gpgconf --query-swdb command.  */
+gpgme_error_t gpgme_op_query_swdb (gpgme_ctx_t ctx,
+                                   const char *name, const char *iversion,
+                                   unsigned int reserved);
+
+/* Return the result from the last query_swdb operation.  */
+gpgme_query_swdb_result_t gpgme_op_query_swdb_result (gpgme_ctx_t ctx);
+
+
+
 

 /*
  * Various functions.
diff --git a/src/libgpgme.vers b/src/libgpgme.vers
index 42f00d5..5457daa 100644
--- a/src/libgpgme.vers
+++ b/src/libgpgme.vers
@@ -122,6 +122,9 @@ GPGME_1.1 {
 
     gpgme_set_sender;
     gpgme_get_sender;
+
+    gpgme_op_query_swdb;
+    gpgme_op_query_swdb_result;
 };
 
 
diff --git a/src/queryswdb.c b/src/queryswdb.c
new file mode 100644
index 0000000..ce50b1e
--- /dev/null
+++ b/src/queryswdb.c
@@ -0,0 +1,121 @@
+/* queryswdb.c - Access to the SWDB file
+ * Copyright (C) 2016 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/>.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <assert.h>
+
+#include "gpgme.h"
+#include "debug.h"
+#include "context.h"
+#include "ops.h"
+
+
+typedef struct
+{
+  struct _gpgme_op_query_swdb_result result;
+
+} *op_data_t;
+
+
+

+static void
+release_op_data (void *hook)
+{
+  op_data_t opd = (op_data_t) hook;
+  gpgme_query_swdb_result_t result = &opd->result;
+
+  assert (!result->next);
+  free (result->name);
+  free (result->iversion);
+  free (result->version);
+}
+
+
+gpgme_query_swdb_result_t
+gpgme_op_query_swdb_result (gpgme_ctx_t ctx)
+{
+  void *hook;
+  op_data_t opd;
+  gpgme_error_t err;
+
+  TRACE_BEG (DEBUG_CTX, "gpgme_op_query_swdb_result", ctx);
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_QUERY_SWDB, &hook, -1, NULL);
+  opd = hook;
+
+  if (err || !opd)
+    {
+      TRACE_SUC0 ("result=(null)");
+      return NULL;
+    }
+
+  TRACE_SUC1 ("result=%p", &opd->result);
+  return &opd->result;
+}
+
+
+
+/* Query the swdb for software package NAME and check against the
+ * installed version given by IVERSION.  If IVERSION is NULL a check
+ * is only done if GPGME can figure out the version by itself
+ * (e.g. for "gpgme" or "gnupg").  RESERVED should be 0.
+ *
+ * Note that we only implemented the synchronous variant of this
+ * function but the API is prepared for an asynchronous variant.
+ */
+gpgme_error_t
+gpgme_op_query_swdb (gpgme_ctx_t ctx, const char *name, const char *iversion,
+                     unsigned int reserved)
+{
+  gpgme_error_t err;
+  void *hook;
+  op_data_t opd;
+
+  TRACE_BEG2 (DEBUG_CTX, "gpgme_op_query_swdb", ctx,
+	      "name=%s, iversion=%a", name, iversion);
+
+  if (!ctx || reserved)
+    return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
+
+  if (ctx->protocol != GPGME_PROTOCOL_GPGCONF)
+    return TRACE_ERR (gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL));
+
+  if (!name)
+    name = "gpgme";
+
+  if (!iversion && !strcmp (name, "gpgme"))
+    iversion = VERSION;
+
+  err = _gpgme_op_reset (ctx, 1);
+  if (err)
+    return err;
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_QUERY_SWDB, &hook,
+                               sizeof (*opd), release_op_data);
+  opd = hook;
+  if (err)
+    return TRACE_ERR (err);
+
+  err = _gpgme_engine_op_query_swdb (ctx->engine, name, iversion,
+                                     &opd->result);
+  return TRACE_ERR (err);
+}
diff --git a/src/util.h b/src/util.h
index 1474b41..a1be6e7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -49,6 +49,11 @@
 # define GPG_ERR_FALSE 256
 #endif
 
+#if GPG_ERROR_VERSION_NUMBER < 0x011900 /* 1.25 */
+# define GPG_ERR_ENGINE_TOO_OLD 300
+# define GPG_ERR_TOO_OLD        308
+#endif
+
 #ifndef GPGRT_ATTR_SENTINEL
 # define GPGRT_ATTR_SENTINEL(a)  /* */
 #endif
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c71914f..e8c7c56 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -33,7 +33,7 @@ noinst_HEADERS = run-support.h
 
 noinst_PROGRAMS = $(TESTS) run-keylist run-export run-import run-sign \
 		  run-verify run-encrypt run-identify run-decrypt run-genkey \
-		  run-keysign run-tofu
+		  run-keysign run-tofu run-swdb
 
 
 if RUN_GPG_TESTS
diff --git a/tests/run-swdb.c b/tests/run-swdb.c
new file mode 100644
index 0000000..91ed22f
--- /dev/null
+++ b/tests/run-swdb.c
@@ -0,0 +1,151 @@
+/* run-swdb.c  - Test tool for SWDB function
+ * Copyright (C) 2016 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 <assert.h>
+
+#include <gpgme.h>
+
+#define PGM "run-swdb"
+
+#include "run-support.h"
+
+
+static int verbose;
+
+
+static const char *
+isotimestr (unsigned long value)
+{
+  time_t t;
+  static char buffer[25+5];
+  struct tm *tp;
+
+  if (!value)
+    return "none";
+  t = value;
+
+  tp = gmtime (&t);
+  snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
+            1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+            tp->tm_hour, tp->tm_min, tp->tm_sec);
+  return buffer;
+}
+
+
+static int
+show_usage (int ex)
+{
+  fputs ("usage: " PGM " [options] NAME [VERSION]\n\n"
+         "Options:\n"
+         "  --verbose        run in verbose mode\n"
+         "  --status         print status lines from the backend\n"
+         , stderr);
+  exit (ex);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  gpgme_error_t err;
+  gpgme_ctx_t ctx;
+  gpgme_protocol_t protocol = GPGME_PROTOCOL_GPGCONF;
+  const char *name;
+  const char *iversion;
+  gpgme_query_swdb_result_t result;
+
+  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 (!strncmp (*argv, "--", 2))
+        show_usage (1);
+    }
+
+  if (argc < 1 || argc > 2)
+    show_usage (1);
+  name = argv[0];
+  iversion = argc > 1? argv[1] : NULL;
+
+  init_gpgme (protocol);
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+  gpgme_set_protocol (ctx, protocol);
+
+  err = gpgme_op_query_swdb (ctx, name, iversion, 0);
+  if (err)
+    {
+      fprintf (stderr, PGM ": error querying swdb: %s\n", gpg_strerror (err));
+      exit (1);
+    }
+
+  result = gpgme_op_query_swdb_result (ctx);
+  if (!result)
+    {
+      fprintf (stderr, PGM ": error querying swdb: %s\n", "no result");
+      exit (1);
+    }
+
+  printf ("package ...: %s\n"
+          "iversion ..: %s\n"
+          "version ...: %s\n",
+          nonnull (result->name),
+          nonnull (result->iversion),
+          nonnull (result->version));
+  printf ("reldate ...: %s\n", isotimestr (result->reldate));
+  printf ("created ...: %s\n", isotimestr (result->created));
+  printf ("retrieved .: %s\n", isotimestr (result->retrieved));
+  printf ("flags .....:%s%s%s%s%s%s%s\n",
+          result->warning? " warning" : "",
+          result->update?  " update"  : "",
+          result->urgent?  " urgent"  : "",
+          result->unknown? " unknown" : "",
+          result->tooold?  " tooold"  : "",
+          result->noinfo?  " noinfo"  : "",
+          result->error?   " error"   : "" );
+
+
+  gpgme_release (ctx);
+  return 0;
+}

-----------------------------------------------------------------------

Summary of changes:
 NEWS                  |   3 +
 doc/gpgme.texi        | 141 ++++++++++++++++++++++++++++++++-
 src/Makefile.am       |   2 +-
 src/context.h         |   3 +-
 src/engine-assuan.c   |   1 +
 src/engine-backend.h  |   4 +
 src/engine-g13.c      |   1 +
 src/engine-gpg.c      |   1 +
 src/engine-gpgconf.c  | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/engine-gpgsm.c    |   1 +
 src/engine-spawn.c    |   1 +
 src/engine-uiserver.c |   1 +
 src/engine.c          |  15 ++++
 src/engine.h          |   6 ++
 src/gpgconf.c         |   4 +-
 src/gpgme.def         |   3 +
 src/gpgme.h.in        |  61 +++++++++++++++
 src/libgpgme.vers     |   3 +
 src/queryswdb.c       | 121 ++++++++++++++++++++++++++++
 src/util.h            |   5 ++
 tests/Makefile.am     |   2 +-
 tests/run-swdb.c      | 151 +++++++++++++++++++++++++++++++++++
 22 files changed, 736 insertions(+), 7 deletions(-)
 create mode 100644 src/queryswdb.c
 create mode 100644 tests/run-swdb.c


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list