aboutsummaryrefslogtreecommitdiffstats
path: root/gpgme/keylist.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpgme/keylist.c')
-rw-r--r--gpgme/keylist.c862
1 files changed, 511 insertions, 351 deletions
diff --git a/gpgme/keylist.c b/gpgme/keylist.c
index 8c78a5f1..09cb89f0 100644
--- a/gpgme/keylist.c
+++ b/gpgme/keylist.c
@@ -1,46 +1,45 @@
-/* keylist.c - key listing
- * Copyright (C) 2000 Werner Koch (dd9jn)
- * Copyright (C) 2001, 2002 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 General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
+/* keylist.c - Listing keys.
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2002 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 General Public License as published by
+ the Free Software Foundation; either version 2 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GPGME; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
#include <config.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
+#include <ctype.h>
#include "util.h"
#include "context.h"
#include "ops.h"
#include "key.h"
-#define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
-
+
struct keylist_result_s
{
int truncated;
GpgmeData xmlinfo;
};
-static void finish_key ( GpgmeCtx ctx );
-
void
_gpgme_release_keylist_result (KeylistResult result)
@@ -50,6 +49,7 @@ _gpgme_release_keylist_result (KeylistResult result)
free (result);
}
+
/* Append some XML info. args is currently ignore but we might want
to add more information in the future (like source of the
keylisting. With args of NULL the XML structure is closed. */
@@ -78,15 +78,11 @@ append_xml_keylistinfo (GpgmeData *rdh, char *args)
return;
}
- _gpgme_data_append_string (dh,
- " <keylisting>\n"
- " <truncated/>\n"
- );
+ _gpgme_data_append_string (dh, " <keylisting>\n <truncated/>\n");
}
-
static void
keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
{
@@ -117,414 +113,577 @@ keylist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
}
}
-
+
static time_t
-parse_timestamp (char *p)
+parse_timestamp (char *timestamp)
{
- if (!*p)
+ if (!*timestamp)
return 0;
- return (time_t)strtoul (p, NULL, 10);
+ return (time_t) strtoul (timestamp, NULL, 10);
}
static void
-set_mainkey_trust_info (GpgmeKey key, const char *s)
+set_mainkey_trust_info (GpgmeKey key, const char *src)
{
/* Look at letters and stop at the first digit. */
- for (; *s && !my_isdigit (*s); s++)
+ while (*src && !isdigit (*src))
{
- switch (*s)
+ switch (*src)
{
- case 'e': key->keys.flags.expired = 1; break;
- case 'r': key->keys.flags.revoked = 1; break;
- case 'd': key->keys.flags.disabled = 1; break;
- case 'i': key->keys.flags.invalid = 1; break;
+ case 'e':
+ key->keys.flags.expired = 1;
+ break;
+
+ case 'r':
+ key->keys.flags.revoked = 1;
+ break;
+
+ case 'd':
+ key->keys.flags.disabled = 1;
+ break;
+
+ case 'i':
+ key->keys.flags.invalid = 1;
+ break;
}
+ src++;
}
}
static void
-set_userid_flags (GpgmeKey key, const char *s)
+set_userid_flags (GpgmeKey key, const char *src)
{
- struct user_id_s *u = key->uids;
-
- assert (u);
- while (u->next)
- u = u->next;
+ struct user_id_s *uid = key->last_uid;
+ assert (uid);
/* Look at letters and stop at the first digit. */
- for (; *s && !my_isdigit (*s); s++)
+ while (*src && !isdigit (*src))
{
- switch (*s)
+ switch (*src)
{
- case 'r': u->revoked = 1; break;
- case 'i': u->invalid = 1; break;
-
- case 'n': u->validity = GPGME_VALIDITY_NEVER; break;
- case 'm': u->validity = GPGME_VALIDITY_MARGINAL; break;
- case 'f': u->validity = GPGME_VALIDITY_FULL; break;
- case 'u': u->validity = GPGME_VALIDITY_ULTIMATE; break;
+ case 'r':
+ uid->revoked = 1;
+ break;
+
+ case 'i':
+ uid->invalid = 1;
+ break;
+
+ case 'n':
+ uid->validity = GPGME_VALIDITY_NEVER;
+ break;
+
+ case 'm':
+ uid->validity = GPGME_VALIDITY_MARGINAL;
+ break;
+
+ case 'f':
+ uid->validity = GPGME_VALIDITY_FULL;
+ break;
+
+ case 'u':
+ uid->validity = GPGME_VALIDITY_ULTIMATE;
+ break;
}
+ src++;
}
}
static void
-set_subkey_trust_info (struct subkey_s *k, const char *s)
+set_subkey_trust_info (struct subkey_s *subkey, const char *src)
{
/* Look at letters and stop at the first digit. */
- for (; *s && !my_isdigit (*s); s++)
+ while (*src && !isdigit (*src))
{
- switch (*s)
+ switch (*src)
{
- case 'e': k->flags.expired = 1; break;
- case 'r': k->flags.revoked = 1; break;
- case 'd': k->flags.disabled = 1; break;
- case 'i': k->flags.invalid = 1; break;
+ case 'e':
+ subkey->flags.expired = 1;
+ break;
+
+ case 'r':
+ subkey->flags.revoked = 1;
+ break;
+
+ case 'd':
+ subkey->flags.disabled = 1;
+ break;
+
+ case 'i':
+ subkey->flags.invalid = 1;
+ break;
}
+ src++;
}
}
static void
-set_mainkey_capability (GpgmeKey key, const char *s)
+set_mainkey_capability (GpgmeKey key, const char *src)
{
- for (; *s ; s++)
+ while (*src)
{
- switch (*s)
+ switch (*src)
{
- case 'e': key->keys.flags.can_encrypt = 1; break;
- case 's': key->keys.flags.can_sign = 1; break;
- case 'c': key->keys.flags.can_certify = 1; break;
- case 'E': key->gloflags.can_encrypt = 1; break;
- case 'S': key->gloflags.can_sign = 1; break;
- case 'C': key->gloflags.can_certify = 1; break;
+ case 'e':
+ key->keys.flags.can_encrypt = 1;
+ break;
+
+ case 's':
+ key->keys.flags.can_sign = 1;
+ break;
+
+ case 'c':
+ key->keys.flags.can_certify = 1;
+ break;
+
+ case 'E':
+ key->gloflags.can_encrypt = 1;
+ break;
+
+ case 'S':
+ key->gloflags.can_sign = 1;
+ break;
+
+ case 'C':
+ key->gloflags.can_certify = 1;
+ break;
}
+ src++;
}
}
static void
-set_subkey_capability ( struct subkey_s *k, const char *s)
+set_subkey_capability (struct subkey_s *subkey, const char *src)
{
- for (; *s; s++)
+ while (*src)
{
- switch (*s)
+ switch (*src)
{
- case 'e': k->flags.can_encrypt = 1; break;
- case 's': k->flags.can_sign = 1; break;
- case 'c': k->flags.can_certify = 1; break;
+ case 'e':
+ subkey->flags.can_encrypt = 1;
+ break;
+
+ case 's':
+ subkey->flags.can_sign = 1;
+ break;
+
+ case 'c':
+ subkey->flags.can_certify = 1;
+ break;
}
+ src++;
}
}
static void
-set_ownertrust (GpgmeKey key, const char *s)
+set_ownertrust (GpgmeKey key, const char *src)
{
/* Look at letters and stop at the first digit. */
- for (; *s && !my_isdigit (*s); s++)
+ while (*src && !isdigit (*src))
{
- switch (*s)
+ switch (*src)
{
- case 'n': key->otrust = GPGME_VALIDITY_NEVER; break;
- case 'm': key->otrust = GPGME_VALIDITY_MARGINAL; break;
- case 'f': key->otrust = GPGME_VALIDITY_FULL; break;
- case 'u': key->otrust = GPGME_VALIDITY_ULTIMATE; break;
- default : key->otrust = GPGME_VALIDITY_UNKNOWN; break;
+ case 'n':
+ key->otrust = GPGME_VALIDITY_NEVER;
+ break;
+
+ case 'm':
+ key->otrust = GPGME_VALIDITY_MARGINAL;
+ break;
+
+ case 'f':
+ key->otrust = GPGME_VALIDITY_FULL;
+ break;
+
+ case 'u':
+ key->otrust = GPGME_VALIDITY_ULTIMATE;
+ break;
+
+ default:
+ key->otrust = GPGME_VALIDITY_UNKNOWN;
+ break;
}
+ src++;
}
}
+/* We have read an entire key into ctx->tmp_key and should now finish
+ it. It is assumed that this releases ctx->tmp_key. */
+static void
+finish_key (GpgmeCtx ctx)
+{
+ GpgmeKey key = ctx->tmp_key;
+
+ ctx->tmp_key = NULL;
+
+ if (key)
+ _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
+}
+
+
/* Note: We are allowed to modify LINE. */
static void
keylist_colon_handler (GpgmeCtx ctx, char *line)
{
- char *p, *pend;
- int field = 0;
enum
{
RT_NONE, RT_SIG, RT_UID, RT_SUB, RT_PUB, RT_FPR, RT_SSB, RT_SEC,
- RT_CRT, RT_CRS
+ RT_CRT, RT_CRS, RT_REV
}
rectype = RT_NONE;
+#define NR_FIELDS 13
+ char *field[NR_FIELDS];
+ int fields = 0;
GpgmeKey key = ctx->tmp_key;
- int i;
- const char *trust_info = NULL;
- struct subkey_s *sk = NULL;
+ struct subkey_s *subkey = NULL;
+ struct certsig_s *certsig = NULL;
+
+ DEBUG3 ("keylist_colon_handler ctx = %p, key = %p, line = %s\n",
+ ctx, key, line ? line : "(null)");
- DEBUG3 ("keylist_colon_handler ctx=%p, key=%p, line=%s\n", ctx, key,
- line? line: "(null)");
if (ctx->error)
return;
+
if (!line)
{
- /* EOF */
+ /* End Of File. */
finish_key (ctx);
return;
}
-
- for (p = line; p; p = pend)
+
+ while (line && fields < NR_FIELDS)
{
- field++;
- pend = strchr (p, ':');
- if (pend)
- *pend++ = 0;
+ field[fields++] = line;
+ line = strchr (line, ':');
+ if (line)
+ *(line++) = '\0';
+ }
- if (field == 1)
+ if (!strcmp (field[0], "sig"))
+ rectype = RT_SIG;
+ else if (!strcmp (field[0], "rev"))
+ rectype = RT_REV;
+ else if (!strcmp (field[0], "uid") && key)
+ rectype = RT_UID;
+ else if (!strcmp (field[0], "sub") && key)
+ {
+ /* Start a new subkey. */
+ rectype = RT_SUB;
+ if (!(subkey = _gpgme_key_add_subkey (key)))
{
- if (!strcmp (p, "sig"))
- rectype = RT_SIG;
- else if (!strcmp (p, "uid") && key)
- {
- rectype = RT_UID;
- key = ctx->tmp_key;
- }
- else if (!strcmp (p, "sub") && key)
- {
- /* Start a new subkey. */
- rectype = RT_SUB;
- if (!(sk = _gpgme_key_add_subkey (key)))
- {
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- }
- else if (!strcmp (p, "ssb") && key)
- {
- /* Start a new secret subkey. */
- rectype = RT_SSB;
- if (!(sk = _gpgme_key_add_secret_subkey (key)))
- {
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- }
- else if (!strcmp (p, "pub"))
- {
- /* Start a new keyblock. */
- if (_gpgme_key_new (&key))
- {
- /* The only kind of error we can get. */
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- rectype = RT_PUB;
- finish_key (ctx);
- assert (!ctx->tmp_key);
- ctx->tmp_key = key;
- }
- else if (!strcmp (p, "sec"))
- {
- /* Start a new keyblock, */
- if (_gpgme_key_new_secret (&key))
- {
- /* The only kind of error we can get. */
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- rectype = RT_SEC;
- finish_key (ctx);
- assert (!ctx->tmp_key);
- ctx->tmp_key = key;
- }
- else if (!strcmp (p, "crt"))
- {
- /* Start a new certificate. */
- if (_gpgme_key_new (&key))
- {
- /* The only kind of error we can get. */
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- key->x509 = 1;
- rectype = RT_CRT;
- finish_key (ctx);
- assert (!ctx->tmp_key);
- ctx->tmp_key = key;
- }
- else if (!strcmp (p, "crs"))
- {
- /* Start a new certificate. */
- if (_gpgme_key_new_secret (&key))
- {
- /* The only kind of error we can get. */
- ctx->error = mk_error (Out_Of_Core);
- return;
- }
- key->x509 = 1;
- rectype = RT_CRS;
- finish_key (ctx);
- assert (!ctx->tmp_key);
- ctx->tmp_key = key;
- }
- else if (!strcmp (p, "fpr") && key)
- rectype = RT_FPR;
- else
- rectype = RT_NONE;
- }
- else if (rectype == RT_PUB || rectype == RT_SEC
- || rectype == RT_CRT || rectype == RT_CRS)
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ }
+ else if (!strcmp (field[0], "ssb") && key)
+ {
+ /* Start a new secret subkey. */
+ rectype = RT_SSB;
+ if (!(subkey = _gpgme_key_add_secret_subkey (key)))
{
- switch (field)
- {
- case 2: /* trust info */
- trust_info = p;
- set_mainkey_trust_info (key, trust_info);
- break;
- case 3: /* key length */
- i = atoi (p);
- if (i > 1) /* ignore invalid values */
- key->keys.key_len = i;
- break;
- case 4: /* pubkey algo */
- i = atoi (p);
- if (i >= 1 && i < 128)
- key->keys.key_algo = i;
- break;
- case 5: /* long keyid */
- if (strlen (p) == DIM(key->keys.keyid) - 1)
- strcpy (key->keys.keyid, p);
- break;
- case 6: /* timestamp (seconds) */
- key->keys.timestamp = parse_timestamp (p);
- break;
- case 7: /* expiration time (seconds) */
- key->keys.expires_at = parse_timestamp (p);
- break;
- case 8: /* X.509 serial number */
- if (rectype == RT_CRT || rectype == RT_CRS)
- {
- key->issuer_serial = strdup (p);
- if (!key->issuer_serial)
- ctx->error = mk_error (Out_Of_Core);
- }
- break;
- case 9: /* ownertrust */
- set_ownertrust (key, p);
- break;
- case 10:
- /* Not used for gpg due to --fixed-list-mode option but
- GPGSM stores the issuer name. */
- if (rectype == RT_CRT || rectype == RT_CRS)
- if (_gpgme_decode_c_string (p, &key->issuer_name))
- ctx->error = mk_error (Out_Of_Core);
- break;
- case 11: /* signature class */
- break;
- case 12: /* capabilities */
- set_mainkey_capability (key, p);
- break;
- case 13:
- pend = NULL; /* we can stop here */
- break;
- }
- }
- else if ((rectype == RT_SUB || rectype== RT_SSB) && sk)
- {
- switch (field)
- {
- case 2: /* trust info */
- set_subkey_trust_info (sk, p);
- break;
- case 3: /* key length */
- i = atoi (p);
- if (i > 1) /* ignore invalid values */
- sk->key_len = i;
- break;
- case 4: /* pubkey algo */
- i = atoi (p);
- if (i >= 1 && i < 128)
- sk->key_algo = i;
- break;
- case 5: /* long keyid */
- if (strlen (p) == DIM(sk->keyid) - 1)
- strcpy (sk->keyid, p);
- break;
- case 6: /* timestamp (seconds) */
- sk->timestamp = parse_timestamp (p);
- break;
- case 7: /* expiration time (seconds) */
- sk->expires_at = parse_timestamp (p);
- break;
- case 8: /* reserved (LID) */
- break;
- case 9: /* ownertrust */
- break;
- case 10:/* user ID n/a for a subkey */
- break;
- case 11: /* signature class */
- break;
- case 12: /* capability */
- set_subkey_capability (sk, p);
- break;
- case 13:
- pend = NULL; /* we can stop here */
- break;
- }
- }
- else if (rectype == RT_UID)
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ }
+ else if (!strcmp (field[0], "pub"))
+ {
+ /* Start a new keyblock. */
+ if (_gpgme_key_new (&key))
{
- switch (field)
- {
- case 2: /* trust info */
- trust_info = p; /*save for later */
- break;
- case 10: /* user ID */
- if (_gpgme_key_append_name (key, p))
- /* The only kind of error we can get*/
- ctx->error = mk_error (Out_Of_Core);
- else
- {
- if (trust_info)
- set_userid_flags (key, trust_info);
- }
- pend = NULL; /* we can stop here */
- break;
- }
- }
- else if (rectype == RT_FPR)
+ /* The only kind of error we can get. */
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ rectype = RT_PUB;
+ finish_key (ctx);
+ assert (!ctx->tmp_key);
+ ctx->tmp_key = key;
+ }
+ else if (!strcmp (field[0], "sec"))
+ {
+ /* Start a new keyblock, */
+ if (_gpgme_key_new_secret (&key))
{
- switch (field)
- {
- case 10: /* fingerprint (take only the first one)*/
- if (!key->keys.fingerprint && *p)
- {
- key->keys.fingerprint = strdup (p);
- if (!key->keys.fingerprint)
- ctx->error = mk_error (Out_Of_Core);
- }
- break;
- case 13: /* gpgsm chain ID (take only the first one)*/
- if (!key->chain_id && *p)
- {
- key->chain_id = strdup (p);
- if (!key->chain_id)
- ctx->error = mk_error (Out_Of_Core);
- }
- pend = NULL; /* that is all we want */
- break;
- }
- }
+ /* The only kind of error we can get. */
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ rectype = RT_SEC;
+ finish_key (ctx);
+ assert (!ctx->tmp_key);
+ ctx->tmp_key = key;
}
-}
+ else if (!strcmp (field[0], "crt"))
+ {
+ /* Start a new certificate. */
+ if (_gpgme_key_new (&key))
+ {
+ /* The only kind of error we can get. */
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ key->x509 = 1;
+ rectype = RT_CRT;
+ finish_key (ctx);
+ assert (!ctx->tmp_key);
+ ctx->tmp_key = key;
+ }
+ else if (!strcmp (field[0], "crs"))
+ {
+ /* Start a new certificate. */
+ if (_gpgme_key_new_secret (&key))
+ {
+ /* The only kind of error we can get. */
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+ key->x509 = 1;
+ rectype = RT_CRS;
+ finish_key (ctx);
+ assert (!ctx->tmp_key);
+ ctx->tmp_key = key;
+ }
+ else if (!strcmp (field[0], "fpr") && key)
+ rectype = RT_FPR;
+ else
+ rectype = RT_NONE;
+
+ /* Only look at signatures immediately following a user ID. For
+ this, clear the user ID pointer when encountering anything but a
+ signature. */
+ if (rectype != RT_SIG && rectype != RT_REV)
+ ctx->tmp_uid = NULL;
+
+ switch (rectype)
+ {
+ case RT_CRT:
+ case RT_CRS:
+ /* Field 8 has the X.509 serial number. */
+ if (fields >= 8)
+ {
+ key->issuer_serial = strdup (field[7]);
+ if (!key->issuer_serial)
+ ctx->error = mk_error (Out_Of_Core);
+ }
+ /* Field 10 is not used for gpg due to --fixed-list-mode option
+ but GPGSM stores the issuer name. */
+ if (fields >= 10 && _gpgme_decode_c_string (field[9],
+ &key->issuer_name, 0))
+ ctx->error = mk_error (Out_Of_Core);
+ /* Fall through! */
+
+ case RT_PUB:
+ case RT_SEC:
+ /* Field 2 has the trust info. */
+ if (fields >= 2)
+ set_mainkey_trust_info (key, field[1]);
+
+ /* Field 3 has the key length. */
+ if (fields >= 3)
+ {
+ int i = atoi (field[2]);
+ /* Ignore invalid values. */
+ if (i > 1)
+ key->keys.key_len = i;
+ }
-/*
- * We have read an entire key into ctx->tmp_key and should now finish
- * it. It is assumed that this releases ctx->tmp_key.
- */
-static void
-finish_key (GpgmeCtx ctx)
-{
- GpgmeKey key = ctx->tmp_key;
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ key->keys.key_algo = i;
+ }
- ctx->tmp_key = NULL;
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(key->keys.keyid) - 1)
+ strcpy (key->keys.keyid, field[4]);
- if (key)
- _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_KEY, key);
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ key->keys.timestamp = parse_timestamp (field[5]);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ key->keys.expires_at = parse_timestamp (field[6]);
+
+ /* Field 9 has the ownertrust. */
+ if (fields >= 9)
+ set_ownertrust (key, field[8]);
+
+ /* Field 11 has the signature class. */
+
+ /* Field 12 has the capabilities. */
+ if (fields >= 12)
+ set_mainkey_capability (key, field[11]);
+ break;
+
+ case RT_SUB:
+ case RT_SSB:
+ /* Field 2 has the trust info. */
+ if (fields >= 2)
+ set_subkey_trust_info (subkey, field[1]);
+
+ /* Field 3 has the key length. */
+ if (fields >= 3)
+ {
+ int i = atoi (field[2]);
+ /* Ignore invalid values. */
+ if (i > 1)
+ subkey->key_len = i;
+ }
+
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ subkey->key_algo = i;
+ }
+
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(subkey->keyid) - 1)
+ strcpy (subkey->keyid, field[4]);
+
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ subkey->timestamp = parse_timestamp (field[5]);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ subkey->expires_at = parse_timestamp (field[6]);
+
+ /* Field 8 is reserved (LID). */
+ /* Field 9 has the ownertrust. */
+ /* Field 10, the user ID, is n/a for a subkey. */
+
+ /* Field 11 has the signature class. */
+
+ /* Field 12 has the capabilities. */
+ if (fields >= 12)
+ set_subkey_capability (subkey, field[11]);
+ break;
+
+ case RT_UID:
+ /* Field 2 has the trust info, and field 10 has the user ID. */
+ if (fields >= 10)
+ {
+ if (_gpgme_key_append_name (key, field[9]))
+ ctx->error = mk_error (Out_Of_Core);
+ else
+ {
+ if (field[1])
+ set_userid_flags (key, field[1]);
+ ctx->tmp_uid = key->last_uid;
+ }
+ }
+ break;
+
+ case RT_FPR:
+ /* Field 10 has the fingerprint (take only the first one). */
+ if (fields >= 10 && !key->keys.fingerprint && field[9] && *field[9])
+ {
+ key->keys.fingerprint = strdup (field[9]);
+ if (!key->keys.fingerprint)
+ ctx->error = mk_error (Out_Of_Core);
+ }
+
+ /* Field 13 has the gpgsm chain ID (take only the first one). */
+ if (fields >= 13 && !key->chain_id && *field[12])
+ {
+ key->chain_id = strdup (field[12]);
+ if (!key->chain_id)
+ ctx->error = mk_error (Out_Of_Core);
+ }
+ break;
+
+ case RT_SIG:
+ case RT_REV:
+ if (!ctx->tmp_uid)
+ return;
+
+ /* Start a new (revoked) signature. */
+ assert (ctx->tmp_uid == key->last_uid);
+ certsig = _gpgme_key_add_certsig (key, (fields >= 10) ? field[9] : NULL);
+ if (!certsig)
+ {
+ ctx->error = mk_error (Out_Of_Core);
+ return;
+ }
+
+ /* Field 2 has the calculated trust ('!', '-', '?', '%'). */
+ if (fields >= 2)
+ switch (field[1][0])
+ {
+ case '!':
+ certsig->sig_stat = GPGME_SIG_STAT_GOOD;
+ break;
+
+ case '-':
+ certsig->sig_stat = GPGME_SIG_STAT_BAD;
+ break;
+
+ case '?':
+ certsig->sig_stat = GPGME_SIG_STAT_NOKEY;
+ break;
+
+ case '%':
+ certsig->sig_stat = GPGME_SIG_STAT_ERROR;
+ break;
+
+ default:
+ certsig->sig_stat = GPGME_SIG_STAT_NONE;
+ break;
+ }
+
+ /* Field 4 has the public key algorithm. */
+ if (fields >= 4)
+ {
+ int i = atoi (field[3]);
+ if (i >= 1 && i < 128)
+ certsig->algo = i;
+ }
+
+ /* Field 5 has the long keyid. */
+ if (fields >= 5 && strlen (field[4]) == DIM(certsig->keyid) - 1)
+ strcpy (certsig->keyid, field[4]);
+
+ /* Field 6 has the timestamp (seconds). */
+ if (fields >= 6)
+ certsig->timestamp = parse_timestamp (field[5]);
+
+ /* Field 7 has the expiration time (seconds). */
+ if (fields >= 7)
+ certsig->expires_at = parse_timestamp (field[6]);
+
+ /* Field 11 has the signature class (eg, 0x30 means revoked). */
+ if (fields >= 11)
+ if (field[10][0] && field[10][1])
+ {
+ int class = _gpgme_hextobyte (field[10]);
+ if (class >= 0)
+ {
+ certsig->sig_class = class;
+ if (class == 0x30)
+ certsig->flags.revoked = 1;
+ }
+ if (field[10][2] == 'x')
+ certsig->flags.exportable = 1;
+ }
+ break;
+
+ case RT_NONE:
+ /* Unknown record. */
+ break;
+ }
}
@@ -593,9 +752,9 @@ gpgme_op_keylist_start (GpgmeCtx ctx, const char *pattern, int secret_only)
if (err)
goto leave;
- /* We don't want to use the verbose mode as this will also print
- the key signatures which is in most cases not needed and furthermore we
- just ignore those lines - This should speed up things */
+ /* We don't want to use the verbose mode as this will also print the
+ key signatures which is in most cases not needed and furthermore
+ we just ignore those lines - This should speed up things. */
_gpgme_engine_set_verbosity (ctx->engine, 0);
err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only,
@@ -647,15 +806,16 @@ gpgme_op_keylist_ext_start (GpgmeCtx ctx, const char *pattern[],
if (err)
goto leave;
- /* We don't want to use the verbose mode as this will also print
- the key signatures which is in most cases not needed and furthermore we
- just ignore those lines - This should speed up things */
+ /* We don't want to use the verbose mode as this will also print the
+ key signatures which is in most cases not needed and furthermore
+ we just ignore those lines - This should speed up things. */
_gpgme_engine_set_verbosity (ctx->engine, 0);
err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only,
reserved, ctx->keylist_mode);
- if (!err) /* And kick off the process. */
+ /* And kick off the process. */
+ if (!err)
err = _gpgme_engine_start (ctx->engine, ctx);
leave: