From 813ae5fa2d712aa9679b791c67c9c1c43d36ffe4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 28 Mar 2017 11:40:44 +0200 Subject: [PATCH] core: Prepare for new key listing data send by gpg. * src/gpgme.h.in (gpgme_user_id_t): New fields 'origin' and 'last_update'. (gpgme_key_t): New fields 'origin' and 'last_update'. * src/conversion.c (_gpgme_parse_timestamp_ul): New. * src/keylist.c (keylist_colon_handler): Parse fields 19 and 20. * tests/run-keylist.c (main): Print new fields. Signed-off-by: Werner Koch --- NEWS | 4 ++++ doc/gpgme.texi | 13 +++++++++++++ src/conversion.c | 19 +++++++++++++++++++ src/gpgme.h.in | 16 ++++++++++++++-- src/keylist.c | 23 ++++++++++++++++------- src/util.h | 3 +++ tests/run-keylist.c | 2 ++ 7 files changed, 71 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index e119b9a3..0005abed 100644 --- a/NEWS +++ b/NEWS @@ -10,7 +10,11 @@ Noteworthy changes in version 1.8.1 (unreleased) gpgme_op_createkey CHANGED: Meaning of 'expire' parameter. gpgme_op_createsubkey CHANGED: Meaning of 'expire' parameter. GPGME_CREATE_NOEXPIRE NEW. + gpgme_key_t EXTENDED: New field 'origin'. + gpgme_key_t EXTENDED: New field 'last_update'. gpgme_subkey_t EXTENDED: New field 'is_de_vs'. + gpgme_user_id_t EXTENDED: New field 'origin'. + gpgme_user_id_t EXTENDED: New field 'last_update'. gpgme_op_keylist_from_data_start NEW. gpgme_op_set_uid_flag_start NEW. gpgme_op_set_uid_flag NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index d5969b71..62004aed 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -3078,6 +3078,9 @@ be true even if the corresponding subkey flag may be false (offline/stub keys). This is only set if a listing of secret keys has been requested or if @code{GPGME_KEYLIST_MODE_WITH_SECRET} is active. +@item unsigned int origin : 5 +Reserved for the origin of this key. + @item gpgme_protocol_t protocol This is the protocol supported by this key. @@ -3111,6 +3114,9 @@ this is a copy of the fingerprint of the first subkey. For an incomplete key (for example from a verification result) a subkey may be missing but this field may be set nevertheless. +@item unsigned long last_update +Reserved for the time of the last update of this key. + @end table @end deftp @@ -3255,6 +3261,13 @@ this user id. @item gpgme_key_sig_t signatures This is a linked list with the signatures on this user ID. + +@item unsigned int origin : 5 +Reserved for the origin of this user ID. + +@item unsigned long last_update +Reserved for the time of the last update of this user ID. + @end table @end deftp diff --git a/src/conversion.c b/src/conversion.c index 6dfabe7e..92dd2141 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -536,6 +536,25 @@ _gpgme_parse_timestamp (const char *timestamp, char **endp) } +/* This function is similar to _gpgme_parse_timestamp but returns an + * unsigned long and 0 on error. */ +unsigned long +_gpgme_parse_timestamp_ul (const char *timestamp) +{ + time_t tim; + char *tail; + + if (!*timestamp) + return 0; /* Shortcut empty strings. */ + + tim = _gpgme_parse_timestamp (timestamp, &tail); + if (tim == -1 || timestamp == tail || (*tail && *tail != ' ')) + tim = 0; /* No time given or invalid engine. */ + + return (unsigned long)tim; +} + + /* The GPG backend uses OpenPGP algorithm numbers which we need to map to our algorithm numbers. This function MUST not change ERRNO. */ int diff --git a/src/gpgme.h.in b/src/gpgme.h.in index b6c14064..24b21e7d 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -662,7 +662,10 @@ struct _gpgme_user_id unsigned int invalid : 1; /* Internal to GPGME, do not use. */ - unsigned int _unused : 30; + unsigned int _unused : 25; + + /* Origin of this user ID. */ + unsigned int origin : 5; /* The validity of the user ID. */ gpgme_validity_t validity; @@ -693,6 +696,9 @@ struct _gpgme_user_id /* The malloced TOFU information or NULL. */ gpgme_tofu_info_t tofu; + + /* Time of the last refresh of thsi user id. 0 if unknown. */ + unsigned long last_update; }; typedef struct _gpgme_user_id *gpgme_user_id_t; @@ -736,7 +742,10 @@ struct _gpgme_key unsigned int is_qualified : 1; /* Internal to GPGME, do not use. */ - unsigned int _unused : 22; + unsigned int _unused : 17; + + /* Origin of this key. */ + unsigned int origin : 5; /* This is the protocol supported by this key. */ gpgme_protocol_t protocol; @@ -776,6 +785,9 @@ struct _gpgme_key * this is a copy of the FPR of the first subkey. We need it here * to allow for an incomplete key object. */ char *fpr; + + /* Time of the last refresh of the entire key. 0 if unknown. */ + unsigned long last_update; }; typedef struct _gpgme_key *gpgme_key_t; diff --git a/src/keylist.c b/src/keylist.c index c88a7ca5..e16ba4d1 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -552,7 +552,7 @@ keylist_colon_handler (void *priv, char *line) RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK } rectype = RT_NONE; -#define NR_FIELDS 18 +#define NR_FIELDS 20 char *field[NR_FIELDS]; int fields = 0; void *hook; @@ -733,6 +733,12 @@ keylist_colon_handler (void *priv, char *line) if (fields >= 17 && *field[17]) parse_pub_field18 (subkey, field[17]); + if (fields >= 20) + { + key->last_update = _gpgme_parse_timestamp_ul (field[18]); + key->origin = 0; /* Fixme: Not yet defined in gpg. */ + } + break; case RT_SUB: @@ -818,12 +824,15 @@ keylist_colon_handler (void *priv, char *line) { if (_gpgme_key_append_name (key, field[9], 1)) return gpg_error (GPG_ERR_ENOMEM); /* FIXME */ - else - { - if (field[1]) - set_userid_flags (key, field[1]); - opd->tmp_uid = key->_last_uid; - } + + if (field[1]) + set_userid_flags (key, field[1]); + opd->tmp_uid = key->_last_uid; + if (fields >= 20) + { + opd->tmp_uid->last_update = _gpgme_parse_timestamp_ul (field[18]); + opd->tmp_uid->origin = 0; /* Fixme: Not yet defined in gpg. */ + } } break; diff --git a/src/util.h b/src/util.h index b27c5833..7b7924cf 100644 --- a/src/util.h +++ b/src/util.h @@ -165,6 +165,9 @@ gpgme_off_t _gpgme_string_to_off (const char *string); point to the next non-parsed character in TIMESTRING. */ time_t _gpgme_parse_timestamp (const char *timestamp, char **endp); +/* Variant of _gpgme_parse_timestamp to return an unsigned long or 0 + * on error or missing timestamp. */ +unsigned long _gpgme_parse_timestamp_ul (const char *timestamp); gpgme_error_t _gpgme_map_gnupg_error (char *err); diff --git a/tests/run-keylist.c b/tests/run-keylist.c index aab4bb64..dd310e5b 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -251,6 +251,7 @@ main (int argc, char **argv) key->is_qualified? " qualified":"", key->subkeys && key->subkeys->is_de_vs? " de-vs":"", key->subkeys && key->subkeys->is_cardkey? " cardkey":""); + printf ("upd : %lu (%u)\n", key->last_update, key->origin); subkey = key->subkeys; if (subkey) @@ -289,6 +290,7 @@ main (int argc, char **argv) printf (" name: %s\n", uid->name); if (uid->comment) printf (" cmmnt: %s\n", uid->comment); + printf (" upd: %lu (%u)\n", uid->last_update, uid->origin); printf (" valid: %s\n", uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown": uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":