diff options
| -rw-r--r-- | NEWS | 9 | ||||
| -rw-r--r-- | doc/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/gpgme.texi | 123 | ||||
| -rw-r--r-- | gpgme/ChangeLog | 26 | ||||
| -rw-r--r-- | gpgme/gpgme.h | 115 | ||||
| -rw-r--r-- | gpgme/import.c | 307 | 
6 files changed, 431 insertions, 154 deletions
| @@ -73,6 +73,11 @@ Noteworthy changes in version 0.4.1 (unreleased)           printf ("%s\n", result->fpr);       } + * The new gpgme_op_import_result function provides detailed +   information about the result of an import operation in +   GpgmeImportResult and GpgmeImportStatus objects.  Thus, the +   gpgme_op_import_ext variant is deprecated. +   * Interface changes relative to the 0.4.0 release:  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  GpgmeIOCb			CHANGED: Return type from void to GpgmeError. @@ -99,6 +104,10 @@ GPGME_Bad_Passphrase		NEW  gpgme_op_genkey			CHANGED: FPR argument dropped.  gpgme_op_genkey_result		NEW  GpgmeGenKeyResult		NEW +gpgme_op_import_ext		DEPRECATED: Use gpgme_op_import_result. +gpgme_op_import_result		NEW +GpgmeImportStatus		NEW +GPgmeImportResult		NEW  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  Noteworthy changes in version 0.4.0 (2002-12-23) diff --git a/doc/ChangeLog b/doc/ChangeLog index 9886a0b7..5f320008 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,6 +1,9 @@  2003-04-25  Marcus Brinkmann  <[email protected]> -	* gpgme.texi (Generating Keys): Fix documentation of ppublic and +	* gpgme.texi (Importing Keys): Add documentation for +	GpgmeImportStatus, GpgmeImportResult and gpgme_op_import_result. + +	* gpgme.texi (Generating Keys): Fix documentation of public and  	secret arguments.  2003-04-24  Marcus Brinkmann  <[email protected]> diff --git a/doc/gpgme.texi b/doc/gpgme.texi index c318f97e..ff519299 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2221,6 +2221,7 @@ successfully.  The returned pointer is only valid until the next  operation is started on the context.  @end deftypefun +  @node Exporting Keys  @subsection Exporting Keys  @cindex key, export @@ -2282,11 +2283,125 @@ started successfully, @code{GPGME_Invalid_Value} if @var{keydata} if  @code{GPGME_No_Data} if @var{keydata} is an empty data buffer.  @end deftypefun +@deftp {Data type} {GpgmeImportStatus} +This is a pointer to a structure used to store a part of the result of +a @code{gpgme_op_genkey} operation.  For each considered key one +status is added that contains information about the result of the +import.  The structure contains the following members: + +@table @code +@item GpgmeImportStatus next +This is a pointer to the next status object in the list. + +@item char *fpr +This is the fingerprint of the key that was considered. + +@item GpgmeError result +If the import was not successful, this is the error value that caused +the import to fail.  Otherwise it is @code{GPGME_No_Error}. + +@item unsigned int status +This is a bit-wise OR of the following flags that give more +information about what part of the key was imported.  If the key was +already known, this might be 0. + +@table @code +@item GPGME_IMPORT_NEW +The key was new. + +@item GPGME_IMPORT_UID +The key contained new user IDs. + +@item GPGME_IMPORT_SIG +The key contained new signatures. + +@item GPGME_IMPORT_SUBKEY +The key contained new sub keys. + +@item GPGME_IMPORT_PRIVATE +The key contained a private key. +@end table +@end table +@end deftp + +@deftp {Data type} {GpgmeImportResult} +This is a pointer to a structure used to store the result of a +@code{gpgme_op_genkey} operation.  After a successful import +operation, you can retrieve the pointer to the result with +@code{gpgme_op_import_result}.  The structure contains the following +members: + +@table @code +@item int considered +The total number of considered keys. + +@item int no_user_id +The number of keys without user ID. + +@item int imported +The total number of imported keys. + +@item imported_rsa +The number of imported RSA keys. + +@item unchanged +The number of unchanged keys. + +@item new_user_ids +The number of new user IDs. + +@item new_sub_keys +The number of new sub keys. + +@item new_signatures +The number of new signatures. + +@item new_revocations +The number of new revocations. + +@item secret_read +The total number of secret keys read. + +@item secret_imported +The number of imported secret keys. + +@item secret_unchanged +The number of unchanged secret keys. + +@item not_imported +The number of keys not imported. + +@item GpgmeImportStatus imports +A list of GpgmeImportStatus objects which contain more information +about the keys for which an import was attempted. +@end table +@end deftp + +@deftypefun GpgmeImportResult gpgme_op_import_result (@w{GpgmeCtx @var{ctx}}) +The function @code{gpgme_op_import_result} returns a +@code{GpgmeImportResult} pointer to a structure holding the result of +a @code{gpgme_op_import} operation.  The pointer is only valid if the +last operation on the context was a @code{gpgme_op_import} or +@code{gpgme_op_import_start} operation, and if this operation finished +successfully.  The returned pointer is only valid until the next +operation is started on the context. +@end deftypefun + +The following interface is deprecated and only provided for backward +compatibility.  Don't use it.  It will be removed in a future version +of @acronym{GPGME}. +  @deftypefun GpgmeError gpgme_op_import_ext (@w{GpgmeCtx @var{ctx}}, @w{GpgmeData @var{keydata}}, @w{int *@var{nr}}) -The function @code{gpgme_op_import_ext} is like -@code{gpgme_op_import}, but also returns the number of processed keys -in @var{nr}.  This is the same as the @code{count} information in the -detailed results available with @code{gpgme_get_op_info}. +The function @code{gpgme_op_import_ext} is equivalent to: + +@example +  GpgmeError err = gpgme_op_import (ctx, keydata); +  if (!err) +    @{ +      GpgmeImportResult result = gpgme_op_import_result (ctx); +      *nr = result->considered; +    @} +@end example  @end deftypefun diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 4b118d5a..1202ea1b 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,31 @@  2003-04-25  Marcus Brinkmann  <[email protected]> +	* gpgme.h: New enum for GPGME_IMPORT_NEW, GPGME_IMPORT_UID, +	GPGME_IMPORT_SIG, GPGME_IMPORT_SUBKEY, GPGME_IMPORT_PRIVATE. +	(GpgmeError): GPGME_Unknown_Reason, GPGME_Not_Found, +	GPGME_Ambiguous_Specification, GPGME_Wrong_Key_Usage, +	GPGME_Key_Revoked, GPGME_Key_Expired, GPGME_No_CRL_Known, +	GPGME_CRL_Too_Old, GPGME_Policy_Mismatch, GPGME_No_Secret_Key, +	GPGME_Key_Not_Trusted, GPGME_Issuer_Missing, GPGME_Chain_Too_Long, +	GPGME_Unsupported_Algorithm, GPGME_Sig_Expired, +	GPGME_Bad_Signature, GPGME_No_Public_Key): New error codes. +	(struct _gpgme_import_status): New structure. +	(GpgmeImportStatus): New type. +	(struct _gpgme_op_import_result): New structure. +	(GpgmeImportResult): New type. +	(gpgme_op_import_result): New function. +	* import.c: Include <errno.h> and "gpgme.h", but not "util.h". +	(struct import_result): Change to type op_data_t. +	(release_import_result): Rename to ... +	(release_op_data): ... this. +	(append_xml_impinfo): Function removed. +	(gpgme_op_import_result): New function. +	(parse_import): New function. +	(parse_import_res): Likewise. +	(import_status_handler): Change first argument to void *.  Rewrite +	to use new functions. +	(_gpgme_op_import_start): Rework error handling. +  	* edit.c: Do not include <assert.h>, "util.h", but "gpgme.h".  	(edit_resut): Change to typedef for op_data_t.  	(edit_status_handler): Change first argument to void *. diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index f7c8b54a..416ae90b 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -96,8 +96,33 @@ typedef enum      GPGME_Invalid_Engine          = 0x0013,      GPGME_No_UserID               = 0x0014,      GPGME_Invalid_UserID          = 0x0015, + +    /* Reasons for invalid user id.  */ +    GPGME_Unknown_Reason          = 0x0100, +    GPGME_Not_Found               = 0x0101, +    GPGME_Ambiguous_Specification = 0x0102, +    GPGME_Wrong_Key_Usage         = 0x0103, +    GPGME_Key_Revoked             = 0x0104, +    GPGME_Key_Expired             = 0x0105, +    GPGME_No_CRL_Known            = 0x0106, +    GPGME_CRL_Too_Old             = 0x0107, +    GPGME_Policy_Mismatch         = 0x0108, +    GPGME_No_Secret_Key           = 0x0109, +    GPGME_Key_Not_Trusted         = 0x010a, +     +    /* Import problems.  */ +    GPGME_Issuer_Missing          = 0x0200, +    GPGME_Chain_Too_Long          = 0x0201, + +    /* Verification problems.  */ +    GPGME_Unsupported_Algorithm   = 0x0300, +    GPGME_Sig_Expired             = 0x0301, +    GPGME_Bad_Signature           = 0x0302, +    GPGME_No_Public_Key           = 0x0303, + +    /* Deprecated.  */      GPGME_Busy                    = -2, -    GPGME_No_Request              = -3, +    GPGME_No_Request              = -3    }  GpgmeError; @@ -750,11 +775,99 @@ GpgmeError gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig,  GpgmeError gpgme_op_verify (GpgmeCtx ctx, GpgmeData sig,  			    GpgmeData signed_text, GpgmeData plaintext); + +enum +  { +    /* The key was new.  */ +    GPGME_IMPORT_NEW = 1, + +    /* The key contained new user IDs.  */ +    GPGME_IMPORT_UID = 2, + +    /* The key contained new signatures.  */ +    GPGME_IMPORT_SIG = 4, + +    /* The key contained new sub keys.  */ +    GPGME_IMPORT_SUBKEY	= 8, + +    /* The key contained a private key.  */ +    GPGME_IMPORT_PRIVATE = 16 +  }; + +struct _gpgme_import_status +{ +  struct _gpgme_import_status *next; + +  /* Fingerprint.  */ +  char *fpr; + +  /* If a problem occured, the reason why the key could not be +     imported.  Otherwise GPGME_No_Error.  */ +  GpgmeError result; + +  /* The result of the import, the GPGME_IMPORT_* values bit-wise +     ORed.  0 means the key was already known and no new components +     have been added.  */ +  unsigned int status; +}; +typedef struct _gpgme_import_status *GpgmeImportStatus; + +/* Import.  */ +struct _gpgme_op_import_result +{ +  /* Number of considered keys.  */ +  int considered; + +  /* Keys without user ID.  */ +  int no_user_id; + +  /* Imported keys.  */ +  int imported; + +  /* Imported RSA keys.  */ +  int imported_rsa; + +  /* Unchanged keys.  */ +  int unchanged; + +  /* Number of new user ids.  */ +  int new_user_ids; + +  /* Number of new sub keys.  */ +  int new_sub_keys; + +  /* Number of new signatures.  */ +  int new_signatures; + +  /* Number of new revocations.  */ +  int new_revocations; + +  /* Number of secret keys read.  */ +  int secret_read; + +  /* Number of secret keys imported.  */ +  int secret_imported; + +  /* Number of secret keys unchanged.  */ +  int secret_unchanged; + +  /* Number of keys not imported.  */ +  int not_imported; + +  /* List of keys for which an import was attempted.  */ +  GpgmeImportStatus imports; +}; +typedef struct _gpgme_op_import_result *GpgmeImportResult; + +/* Retrieve a pointer to the result of the import operation.  */ +GpgmeImportResult gpgme_op_import_result (GpgmeCtx ctx); +  /* Import the key in KEYDATA into the keyring.  */  GpgmeError gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata);  GpgmeError gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata);  GpgmeError gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr); +  /* Export the keys listed in RECP into KEYDATA.  */  GpgmeError gpgme_op_export_start (GpgmeCtx ctx, GpgmeRecipients recp,  				  GpgmeData keydata); diff --git a/gpgme/import.c b/gpgme/import.c index 3c050b19..c9fff5b5 100644 --- a/gpgme/import.c +++ b/gpgme/import.c @@ -1,4 +1,4 @@ -/* import.c - Import functions. +/* import.c - Import a key.     Copyright (C) 2000 Werner Koch (dd9jn)     Copyright (C) 2001, 2002, 2003 g10 Code GmbH @@ -22,155 +22,183 @@  #include <config.h>  #endif  #include <stdlib.h> +#include <errno.h>  #include <string.h> -#include "util.h" +#include "gpgme.h"  #include "context.h"  #include "ops.h" -struct import_result +typedef struct  { -  int nr_imported; -  int nr_considered; -  GpgmeData xmlinfo; -}; -typedef struct import_result *ImportResult; +  struct _gpgme_op_import_result result; + +  /* A pointer to the next pointer of the last import status in the +     list.  This makes appending new imports painless while preserving +     the order.  */ +  GpgmeImportStatus *lastp; +} *op_data_t; +  static void -release_import_result (void *hook) +release_op_data (void *hook)  { -  ImportResult result = (ImportResult) hook; +  op_data_t opd = (op_data_t) hook; +  GpgmeImportStatus import = opd->result.imports; -  if (result->xmlinfo) -    gpgme_data_release (result->xmlinfo); +  while (import) +    { +      GpgmeImportStatus next = import->next; +      free (import->fpr); +      free (import); +      import = next; +    }  } -/* Parse the args and append the information to the XML structure in -   the data buffer.  With args of NULL the xml structure is -   closed.  */ -static void -append_xml_impinfo (GpgmeData *rdh, GpgmeStatusCode code, char *args) +GpgmeImportResult +gpgme_op_import_result (GpgmeCtx ctx)  { -#define MAX_IMPORTED_FIELDS 14 -  static const char *const imported_fields[MAX_IMPORTED_FIELDS] -    = { "keyid", "username", 0 }; -  static const char *const imported_fields_x509[MAX_IMPORTED_FIELDS] -    = { "fpr", 0 }; -  static const char *const import_res_fields[MAX_IMPORTED_FIELDS] -    = { "count", "no_user_id", "imported", "imported_rsa", -	"unchanged", "n_uids", "n_subk", "n_sigs", "s_sigsn_revoc", -	"sec_read", "sec_imported", "sec_dups", "skipped_new", 0 }; -  const char *field[MAX_IMPORTED_FIELDS]; -  const char *const *field_name = 0; -  GpgmeData dh; -  int i; - -  /* Verify that we can use the args.  */ -  if (code != GPGME_STATUS_EOF) -    { -      if (!args) -	return; +  op_data_t opd; +  GpgmeError err; -      if (code == GPGME_STATUS_IMPORTED) -	field_name = imported_fields; -      else if (code == GPGME_STATUS_IMPORT_RES) -	field_name = import_res_fields; -      else -	return; +  err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd, -1, NULL); +  if (err || !opd) +    return NULL; -      for (i = 0; field_name[i]; i++) -	{ -	  field[i] = args; -	  if (field_name[i + 1]) -	    { -	      args = strchr (args, ' '); -	      if (!args) -		return;  /* Invalid line.  */ -	      *args++ = '\0'; -	    } -	} -       -      /* gpgsm does not print a useful user ID and uses a fingerprint -         instead of the key ID. */ -      if (code == GPGME_STATUS_IMPORTED && field[0] && strlen (field[0]) > 16) -        field_name = imported_fields_x509; -    } +  return &opd->result; +} -  /* Initialize the data buffer if necessary.  */ -  if (!*rdh) + +static GpgmeError +parse_import (char *args, GpgmeImportStatus *import_status, int problem) +{ +  GpgmeImportStatus import; +  char *tail; +  long int nr; + +  import = malloc (sizeof (*import)); +  if (!import) +    return GPGME_Out_Of_Core; +  import->next = NULL; + +  errno = 0; +  nr = strtol (args, &tail, 0); +  if (errno || args == tail || *tail != ' ')      { -      if (gpgme_data_new (rdh)) -        return; /* FIXME: We are ignoring out-of-core.  */ -      dh = *rdh; -      _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n"); +      /* The crypto backend does not behave.  */ +      free (import); +      return GPGME_General_Error;      } -  else -    dh = *rdh; -     -  if (code == GPGME_STATUS_EOF) +  args = tail; + +  if (problem)      { -      /* Just close the XML containter.  */ -      _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n"); +      switch (nr) +	{ +	case 0: +	case 4: +	default: +	  import->result = GPGME_Unknown_Reason; +	  break; + +	case 1: +	  import->result = GPGME_Invalid_Key; +	  break; + +	case 2: +	  import->result = GPGME_Issuer_Missing; +	  break; + +	case 3: +	  import->result = GPGME_Chain_Too_Long; +	  break; +	} +      import->status = 0;      }    else      { -      if (code == GPGME_STATUS_IMPORTED) -	_gpgme_data_append_string (dh, "  <import>\n"); -      else if (code == GPGME_STATUS_IMPORT_RES) -	_gpgme_data_append_string (dh, "  <importResult>\n"); +      import->result = GPGME_No_Error; +      import->status = nr; +    } -      for (i = 0; field_name[i]; i++) -	{ -	  _gpgme_data_append_string (dh, "    <"); -          _gpgme_data_append_string (dh, field_name[i]); -	  _gpgme_data_append_string (dh, ">"); -	  _gpgme_data_append_string_for_xml (dh, field[i]); -	  _gpgme_data_append_string (dh, "</"); -	  _gpgme_data_append_string (dh, field_name[i]); -	  _gpgme_data_append_string (dh, ">\n"); -	} +  while (*args == ' ') +    args++; +  tail = strchr (args, ' '); +  if (tail) +    *tail = '\0'; -      if (code == GPGME_STATUS_IMPORTED) -	_gpgme_data_append_string (dh, "  </import>\n"); -      else if (code == GPGME_STATUS_IMPORT_RES) -	_gpgme_data_append_string (dh, "  </importResult>\n"); +  import->fpr = strdup (args); +  if (!import->fpr) +    { +      free (import); +      return GPGME_Out_Of_Core;      } + +  *import_status = import; +  return 0; +} + + + +GpgmeError +parse_import_res (char *args, GpgmeImportResult result) +{ +  char *tail; + +  errno = 0; + +#define PARSE_NEXT(x)					\ +  (x) = strtol (args, &tail, 0);			\ +  if (errno || args == tail || *tail != ' ')		\ +    /* The crypto backend does not behave.  */		\ +    return GPGME_General_Error;				\ +  args = tail; + +  PARSE_NEXT (result->considered); +  PARSE_NEXT (result->no_user_id); +  PARSE_NEXT (result->imported); +  PARSE_NEXT (result->imported_rsa); +  PARSE_NEXT (result->new_user_ids); +  PARSE_NEXT (result->new_sub_keys); +  PARSE_NEXT (result->new_signatures); +  PARSE_NEXT (result->new_revocations); +  PARSE_NEXT (result->secret_read); +  PARSE_NEXT (result->secret_imported); +  PARSE_NEXT (result->secret_unchanged); +  PARSE_NEXT (result->not_imported); + +  return 0;  }  static GpgmeError -import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) +import_status_handler (void *priv, GpgmeStatusCode code, char *args)  { +  GpgmeCtx ctx = (GpgmeCtx) priv;    GpgmeError err; -  ImportResult result; +  op_data_t opd; -  err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &result, -			       sizeof (*result), release_import_result); +  err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd, +			       -1, NULL);    if (err)      return err;    switch (code)      { -    case GPGME_STATUS_EOF: -      if (result->xmlinfo) -        { -          append_xml_impinfo (&result->xmlinfo, code, NULL); -          _gpgme_set_op_info (ctx, result->xmlinfo); -          result->xmlinfo = NULL; -        } -      /* XXX Calculate error value.  */ -      break; - -    case GPGME_STATUS_IMPORTED: -      result->nr_imported++; -      append_xml_impinfo (&result->xmlinfo, code, args); +    case GPGME_STATUS_IMPORT_OK: +    case GPGME_STATUS_IMPORT_PROBLEM: +      err = parse_import (args, opd->lastp, +			  code == GPGME_STATUS_IMPORT_OK ? 0 : 1); +      if (err) +	return err; + +      opd->lastp = &(*opd->lastp)->next;        break;      case GPGME_STATUS_IMPORT_RES: -      result->nr_considered = strtol (args, 0, 0); -      append_xml_impinfo (&result->xmlinfo, code, args); +      err = parse_import_res (args, &opd->result);        break;      default: @@ -183,30 +211,25 @@ import_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)  static GpgmeError  _gpgme_op_import_start (GpgmeCtx ctx, int synchronous, GpgmeData keydata)  { -  int err = 0; +  GpgmeError err; +  op_data_t opd;    err = _gpgme_op_reset (ctx, synchronous);    if (err) -    goto leave; +    return err; + +  err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &opd, +			       sizeof (*opd), release_op_data); +  if (err) +    return err; +  opd->lastp = &opd->result.imports; -  /* Check the supplied data */    if (!keydata) -    { -      err = GPGME_No_Data; -      goto leave; -    } +    return GPGME_No_Data;    _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); -  err = _gpgme_engine_op_import (ctx->engine, keydata); - - leave: -  if (err) -    { -      _gpgme_engine_release (ctx->engine); -      ctx->engine = NULL; -    } -  return err; +  return _gpgme_engine_op_import (ctx->engine, keydata);  } @@ -216,38 +239,26 @@ gpgme_op_import_start (GpgmeCtx ctx, GpgmeData keydata)    return _gpgme_op_import_start (ctx, 0, keydata);  } -/** - * gpgme_op_import: - * @c: Context  - * @keydata: Data object - * @nr: Will contain number of considered keys. - *  - * Import all key material from @keydata into the key database. - *  - * Return value: 0 on success or an error code. - **/ + +/* Import the key in KEYDATA into the keyring.  */  GpgmeError -gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr) +gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata)  {    GpgmeError err = _gpgme_op_import_start (ctx, 1, keydata);    if (!err)      err = _gpgme_wait_one (ctx); -  if (!err && nr) -    { -      ImportResult result; - -      err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, (void **) &result, -				   -1, NULL); -      if (result) -	*nr = result->nr_considered; -      else -	*nr = 0; -    }    return err;  } +  GpgmeError -gpgme_op_import (GpgmeCtx ctx, GpgmeData keydata) +gpgme_op_import_ext (GpgmeCtx ctx, GpgmeData keydata, int *nr)  { -  return gpgme_op_import_ext (ctx, keydata, 0); +  GpgmeError err = gpgme_op_import (ctx, keydata); +  if (!err && nr) +    { +      GpgmeImportResult result = gpgme_op_import_result (ctx); +      *nr = result->considered; +    } +  return err;  } | 
