[Pkg-gnupg-commit] [gpgme] 17/62: core: Add gpgme_op_query_swdb and helper.
Daniel Kahn Gillmor
dkg at fifthhorseman.net
Sat Nov 19 04:03:32 UTC 2016
This is an automated email from the git hooks/post-receive script.
dkg pushed a commit to branch experimental
in repository gpgme.
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>
---
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(-)
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;
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gpgme.git
More information about the Pkg-gnupg-commit
mailing list