diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp index 4b370207..eb7a5030 100644 --- a/lang/cpp/src/key.cpp +++ b/lang/cpp/src/key.cpp @@ -723,6 +723,56 @@ TofuInfo UserID::tofuInfo() const return TofuInfo(uid->tofu); } +static gpgme_key_sig_t find_last_valid_sig_for_keyid (gpgme_user_id_t uid, + const char *keyid) +{ + if (!keyid) { + return nullptr; + } + gpgme_key_sig_t ret = NULL; + for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) { + if (s->keyid && !strcmp(keyid, s->keyid)) { + if (!s->expired && !s->revoked && !s->invalid && !s->status) { + if (!ret) { + ret = s; + } else if (ret && ret->timestamp <= s->timestamp) { + /* Equals because when the timestamps are the same we prefer + the last in the list */ + ret = s; + } + } + } + } + return ret; +} + +const char *UserID::remark(const Key &remarker, Error &err) const +{ + if (!uid || remarker.isNull()) { + err = Error::fromCode(GPG_ERR_GENERAL); + return nullptr; + } + + if (!(parent().keyListMode() & GPGME_KEYLIST_MODE_SIG_NOTATIONS) || + !(parent().keyListMode() & GPGME_KEYLIST_MODE_SIGS)) { + err = Error::fromCode(GPG_ERR_NO_DATA); + return nullptr; + } + + gpgme_key_sig_t s = find_last_valid_sig_for_keyid(uid, remarker.keyID()); + + if (!s) { + return nullptr; + } + + for (gpgme_sig_notation_t n = s->notations; n ; n = n->next) { + if (n->name && !strcmp(n->name, "rem@gnupg.org")) { + return n->value; + } + } + return nullptr; +} + // // // class Signature diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h index dd855aec..cca3c7a6 100644 --- a/lang/cpp/src/key.h +++ b/lang/cpp/src/key.h @@ -413,6 +413,23 @@ public: * * @returns the last update time. */ time_t lastUpdate() const; + + /*! Get a remark made by the key provided. + * A remark is a signature notation on + * this user id made by the key with the + * name "rem@gnupg.org". Returns an error if the + * parent key of this user id was not listed with the + * keylist mode flags for signatures and signature notations. + * + * @param key The key for which comments should be searched. + * @param error Set to GPG_ERR_NO_DATA if the keylist did + * not include signature notations. + * + * @returns The value of the comment or NULL if none exists. + **/ + const char *remark(const Key &key, + Error &error) const; + private: shared_gpgme_key_t key; gpgme_user_id_t uid;