diff options
Diffstat (limited to '')
| -rw-r--r-- | NEWS | 3 | ||||
| -rw-r--r-- | doc/gpgme.texi | 141 | ||||
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/context.h | 3 | ||||
| -rw-r--r-- | src/engine-assuan.c | 1 | ||||
| -rw-r--r-- | src/engine-backend.h | 4 | ||||
| -rw-r--r-- | src/engine-g13.c | 1 | ||||
| -rw-r--r-- | src/engine-gpg.c | 1 | ||||
| -rw-r--r-- | src/engine-gpgconf.c | 213 | ||||
| -rw-r--r-- | src/engine-gpgsm.c | 1 | ||||
| -rw-r--r-- | src/engine-spawn.c | 1 | ||||
| -rw-r--r-- | src/engine-uiserver.c | 1 | ||||
| -rw-r--r-- | src/engine.c | 15 | ||||
| -rw-r--r-- | src/engine.h | 6 | ||||
| -rw-r--r-- | src/gpgconf.c | 4 | ||||
| -rw-r--r-- | src/gpgme.def | 3 | ||||
| -rw-r--r-- | src/gpgme.h.in | 61 | ||||
| -rw-r--r-- | src/libgpgme.vers | 3 | ||||
| -rw-r--r-- | src/queryswdb.c | 121 | ||||
| -rw-r--r-- | src/util.h | 5 | ||||
| -rw-r--r-- | tests/Makefile.am | 2 | ||||
| -rw-r--r-- | tests/run-swdb.c | 151 | 
22 files changed, 736 insertions, 7 deletions
| @@ -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 9fae9aaf..a70418db 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 +@node Checking for updates +@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. + +@deftp {Data type} {gpgme_query_swdb_result_t} +This is a pointer to a structure used to store the result of a +@code{gpgme_op_query_swdb} operation.  After success full call to that +function, you can retrieve the pointer to the result with +@code{gpgme_op_query_swdb_result}.  The structure contains the +following member: + +@table @code +@item name +This is the name of the package. + +@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. + +@item created +This gives the date the file with the list of version numbers has +originally be created by the GnuPG project. + +@item retrieved +This gives the date the file was downloaded. + +@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. + +@item update +If this flag is set an update of the software is available. + +@item urgent +If this flag is set an available update is important. + +@item noinfo +If this flag is set, no valid information could be retrieved. + +@item unknown +If this flag is set the given @code{name} is not known. + +@item tooold +If this flag is set the available information is not fresh enough. + +@item error +If this flag is set some other error has occured. + +@item version +The version string of the latest released version. + +@item reldate +The release date of the latest released version. + +@end table +@end deftp + +@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 +@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. + +@end deftypefun + +@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 +@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 +@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}. +@end deftypefun + +@noindent +Here is an example on how to check whether GnuPG is current: + +@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; +@} +@end example + +  @node Run Control  @section Run Control  @cindex run control diff --git a/src/Makefile.am b/src/Makefile.am index f166f3b2..eddd1920 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 f6c1ad1e..00e2e779 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 65924eb2..4c7fe281 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 e02c7157..a8b1ac60 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 d34db829..972c3a8a 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 cb52dea7..7725a001 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 271a4dda..25c798e6 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 0ce4a6d1..a815cf00 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 df90cb23..d2c7dd62 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 76fa4d79..47b7dc33 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 f5dfe51f..4e513b6d 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 2999ab64..15b0b5d4 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 65914529..b1b84a62 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 d633df57..2f6837da 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 94ef51de..4f470a03 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 42f00d5a..5457daa4 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 00000000..ce50b1e8 --- /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); +} @@ -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 c71914f3..e8c7c564 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 00000000..91ed22f3 --- /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; +} | 
