diff --git a/src/key.cpp b/src/key.cpp
index b7a55aec..b18cfaee 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,1317 +1,1312 @@
 /*
   key.cpp - wraps a gpgme key
   Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
 
   This file is part of GPGME++.
 
   GPGME++ is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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 Library General Public License for more details.
 
   You should have received a copy of the GNU Library General Public License
   along with GPGME++; see the file COPYING.LIB.  If not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
 */
 
 #ifdef HAVE_CONFIG_H
  #include "config.h"
 #endif
 
 #include <key.h>
 
 #include "util.h"
 #include "tofuinfo.h"
 #include "context.h"
 #include "engineinfo.h"
 
 #include <gpgme.h>
 
 #include <string.h>
 #include <strings.h>
 #include <cassert>
 #include <istream>
 #include <iterator>
 
 const GpgME::Key::Null GpgME::Key::null;
 
 namespace GpgME
 {
 
 Key::Key() : key() {}
 
 Key::Key(const Null &) : key() {}
 
 Key::Key(const shared_gpgme_key_t &k) : key(k) {}
 
 Key::Key(gpgme_key_t k, bool ref)
     : key(k
           ? shared_gpgme_key_t(k, &gpgme_key_unref)
           : shared_gpgme_key_t())
 {
     if (ref && impl()) {
         gpgme_key_ref(impl());
     }
 }
 
 UserID Key::userID(unsigned int index) const
 {
     return UserID(key, index);
 }
 
 Subkey Key::subkey(unsigned int index) const
 {
     return Subkey(key, index);
 }
 
 unsigned int Key::numUserIDs() const
 {
     if (!key) {
         return 0;
     }
     unsigned int count = 0;
     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
         ++count;
     }
     return count;
 }
 
 unsigned int Key::numSubkeys() const
 {
     if (!key) {
         return 0;
     }
     unsigned int count = 0;
     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
         ++count;
     }
     return count;
 }
 
 std::vector<UserID> Key::userIDs() const
 {
     if (!key) {
         return std::vector<UserID>();
     }
 
     std::vector<UserID> v;
     v.reserve(numUserIDs());
     for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
         v.push_back(UserID(key, uid));
     }
     return v;
 }
 
 std::vector<Subkey> Key::subkeys() const
 {
     if (!key) {
         return std::vector<Subkey>();
     }
 
     std::vector<Subkey> v;
     v.reserve(numSubkeys());
     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
         v.push_back(Subkey(key, subkey));
     }
     return v;
 }
 
 Key::OwnerTrust Key::ownerTrust() const
 {
     if (!key) {
         return Unknown;
     }
     switch (key->owner_trust) {
     default:
     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
     case GPGME_VALIDITY_UNDEFINED: return Undefined;
     case GPGME_VALIDITY_NEVER:     return Never;
     case GPGME_VALIDITY_MARGINAL:  return Marginal;
     case GPGME_VALIDITY_FULL:     return Full;
     case GPGME_VALIDITY_ULTIMATE: return Ultimate;
     }
 }
 char Key::ownerTrustAsString() const
 {
     if (!key) {
         return '?';
     }
     switch (key->owner_trust) {
     default:
     case GPGME_VALIDITY_UNKNOWN:   return '?';
     case GPGME_VALIDITY_UNDEFINED: return 'q';
     case GPGME_VALIDITY_NEVER:     return 'n';
     case GPGME_VALIDITY_MARGINAL:  return 'm';
     case GPGME_VALIDITY_FULL:     return 'f';
     case GPGME_VALIDITY_ULTIMATE: return 'u';
     }
 }
 
 Protocol Key::protocol() const
 {
     if (!key) {
         return UnknownProtocol;
     }
     switch (key->protocol) {
     case GPGME_PROTOCOL_CMS:     return CMS;
     case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
     default:                     return UnknownProtocol;
     }
 }
 
 const char *Key::protocolAsString() const
 {
     return key ? gpgme_get_protocol_name(key->protocol) : nullptr ;
 }
 
 bool Key::isRevoked() const
 {
     return key && key->revoked;
 }
 
 bool Key::isExpired() const
 {
     return key && key->expired;
 }
 
 bool Key::isDisabled() const
 {
     return key && key->disabled;
 }
 
 bool Key::isInvalid() const
 {
     return key && key->invalid;
 }
 
 bool Key::hasSecret() const
 {
     return key && key->secret;
 }
 
 bool Key::isRoot() const
 {
     return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
            strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
 }
 
 bool Key::canEncrypt() const
 {
     return key && key->can_encrypt;
 }
 
 bool Key::canSign() const
 {
-#ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
-    if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
-        return true;
-    }
-#endif
-    return canReallySign();
+    return key && key->can_sign;
 }
 
 bool Key::canReallySign() const
 {
-    return key && key->can_sign;
+    return canSign();
 }
 
 bool Key::canCertify() const
 {
     return key && key->can_certify;
 }
 
 bool Key::canAuthenticate() const
 {
     return key && key->can_authenticate;
 }
 
 bool Key::isQualified() const
 {
     return key && key->is_qualified;
 }
 
 bool Key::isDeVs() const
 {
     if (!key) {
         return false;
     }
     if (!key->subkeys || !key->subkeys->is_de_vs) {
         return false;
     }
     for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
         if (!subkey->is_de_vs) {
             return false;
         }
     }
     return true;
 }
 
 const char *Key::issuerSerial() const
 {
     return key ? key->issuer_serial : nullptr ;
 }
 const char *Key::issuerName() const
 {
     return key ? key->issuer_name : nullptr ;
 }
 const char *Key::chainID() const
 {
     return key ? key->chain_id : nullptr ;
 }
 
 const char *Key::keyID() const
 {
     return key && key->subkeys ? key->subkeys->keyid : nullptr ;
 }
 
 const char *Key::shortKeyID() const
 {
     if (!key || !key->subkeys || !key->subkeys->keyid) {
         return nullptr;
     }
     const int len = strlen(key->subkeys->keyid);
     if (len > 8) {
         return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
     } else {
         return key->subkeys->keyid;
     }
 }
 
 const char *Key::primaryFingerprint() const
 {
     if (!key) {
         return nullptr;
     }
     if (key->fpr) {
         /* Return what gpgme thinks is the primary fingerprint */
         return key->fpr;
     }
     if (key->subkeys) {
         /* Return the first subkeys fingerprint */
         return key->subkeys->fpr;
     }
     return nullptr;
 }
 
 unsigned int Key::keyListMode() const
 {
     return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0;
 }
 
 const Key &Key::mergeWith(const Key &other)
 {
     // ### incomplete. Just merges has* and can*, nothing else atm
     // ### detach also missing
 
     if (!this->primaryFingerprint() ||
             !other.primaryFingerprint() ||
             strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
         return *this; // only merge the Key object which describe the same key
     }
 
     const gpgme_key_t me = impl();
     const gpgme_key_t him = other.impl();
 
     if (!me || !him) {
         return *this;
     }
 
     me->revoked          |= him->revoked;
     me->expired          |= him->expired;
     me->disabled         |= him->disabled;
     me->invalid          |= him->invalid;
     me->can_encrypt      |= him->can_encrypt;
     me->can_sign         |= him->can_sign;
     me->can_certify      |= him->can_certify;
     me->secret           |= him->secret;
     me->can_authenticate |= him->can_authenticate;
     me->is_qualified     |= him->is_qualified;
     me->keylist_mode     |= him->keylist_mode;
 
     // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
     for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
         for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
             if (strcmp(mysk->fpr, hissk->fpr) == 0) {
                 mysk->is_cardkey |= hissk->is_cardkey;
                 mysk->secret |= hissk->secret;
                 if (hissk->keygrip && !mysk->keygrip) {
                     mysk->keygrip = strdup(hissk->keygrip);
                 }
                 break;
             }
         }
     }
 
     return *this;
 }
 
 void Key::update()
 {
     if (isNull() || !primaryFingerprint()) {
         return;
     }
     auto ctx = Context::createForProtocol(protocol());
     if (!ctx) {
         return;
     }
     ctx->setKeyListMode(KeyListMode::Local |
                         KeyListMode::Signatures |
                         KeyListMode::SignatureNotations |
                         KeyListMode::Validate |
                         KeyListMode::WithTofu |
                         KeyListMode::WithKeygrip |
                         KeyListMode::WithSecret);
     Error err;
     Key newKey;
     if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.0") {
         newKey = ctx->key(primaryFingerprint(), err, true);
         // Not secret so we get the information from the pubring.
         if (newKey.isNull()) {
             newKey = ctx->key(primaryFingerprint(), err, false);
         }
     } else {
         newKey = ctx->key(primaryFingerprint(), err, false);
     }
     delete ctx;
     if (err) {
         return;
     }
     swap(newKey);
 }
 
 // static
 Key Key::locate(const char *mbox)
 {
     if (!mbox) {
         return Key();
     }
 
     auto ctx = Context::createForProtocol(OpenPGP);
     if (!ctx) {
         return Key();
     }
 
     ctx->setKeyListMode (Extern | Local);
 
     Error e = ctx->startKeyListing (mbox);
     auto ret = ctx->nextKey (e);
     delete ctx;
 
     return ret;
 }
 
 //
 //
 // class Subkey
 //
 //
 
 static gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
 {
     if (key) {
         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
             if (idx == 0) {
                 return s;
             }
         }
     }
     return nullptr;
 }
 
 static gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
 {
     if (key) {
         for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
             if (s == subkey) {
                 return subkey;
             }
         }
     }
     return nullptr;
 }
 
 Subkey::Subkey() : key(), subkey(nullptr) {}
 
 Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
     : key(k), subkey(find_subkey(k, idx))
 {
 
 }
 
 Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
     : key(k), subkey(verify_subkey(k, sk))
 {
 
 }
 
 Key Subkey::parent() const
 {
     return Key(key);
 }
 
 const char *Subkey::keyID() const
 {
     return subkey ? subkey->keyid : nullptr ;
 }
 
 const char *Subkey::fingerprint() const
 {
     return subkey ? subkey->fpr : nullptr ;
 }
 
 Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
 {
     return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
 }
 
 const char *Subkey::publicKeyAlgorithmAsString() const
 {
     return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
 }
 
 /* static */
 const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
 {
     if (algo == AlgoUnknown) {
         return NULL;
     }
     return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
 }
 
 std::string Subkey::algoName() const
 {
     char *gpgmeStr;
     if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
         std::string ret = std::string(gpgmeStr);
         gpgme_free(gpgmeStr);
         return ret;
     }
     return std::string();
 }
 
 bool Subkey::canEncrypt() const
 {
     return subkey && subkey->can_encrypt;
 }
 
 bool Subkey::canSign() const
 {
     return subkey && subkey->can_sign;
 }
 
 bool Subkey::canCertify() const
 {
     return subkey && subkey->can_certify;
 }
 
 bool Subkey::canAuthenticate() const
 {
     return subkey && subkey->can_authenticate;
 }
 
 bool Subkey::canRenc() const
 {
     return subkey && subkey->can_renc;
 }
 
 bool Subkey::canTimestamp() const
 {
     return subkey && subkey->can_timestamp;
 }
 
 bool Subkey::isGroupOwned() const
 {
     return subkey && subkey->is_group_owned;
 }
 
 bool Subkey::isQualified() const
 {
     return subkey && subkey->is_qualified;
 }
 
 bool Subkey::isDeVs() const
 {
     return subkey && subkey->is_de_vs;
 }
 
 bool Subkey::isCardKey() const
 {
     return subkey && subkey->is_cardkey;
 }
 
 const char *Subkey::cardSerialNumber() const
 {
     return subkey ? subkey->card_number : nullptr;
 }
 
 const char *Subkey::keyGrip() const
 {
     return subkey ? subkey->keygrip : nullptr;
 }
 
 bool Subkey::isSecret() const
 {
     return subkey && subkey->secret;
 }
 
 unsigned int Subkey::length() const
 {
     return subkey ? subkey->length : 0 ;
 }
 
 time_t Subkey::creationTime() const
 {
     return static_cast<time_t>(subkey ? subkey->timestamp : 0);
 }
 
 time_t Subkey::expirationTime() const
 {
     return static_cast<time_t>(subkey ? subkey->expires : 0);
 }
 
 bool Subkey::neverExpires() const
 {
     return expirationTime() == time_t(0);
 }
 
 bool Subkey::isRevoked() const
 {
     return subkey && subkey->revoked;
 }
 
 bool Subkey::isInvalid() const
 {
     return subkey && subkey->invalid;
 }
 
 bool Subkey::isExpired() const
 {
     return subkey && subkey->expired;
 }
 
 bool Subkey::isDisabled() const
 {
     return subkey && subkey->disabled;
 }
 
 //
 //
 // class UserID
 //
 //
 
 static gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
 {
     if (key) {
         for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
             if (idx == 0) {
                 return u;
             }
         }
     }
     return nullptr;
 }
 
 static gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
 {
     if (key) {
         for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
             if (u == uid) {
                 return uid;
             }
         }
     }
     return nullptr;
 }
 
 UserID::UserID() : key(), uid(nullptr) {}
 
 UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
     : key(k), uid(verify_uid(k, u))
 {
 
 }
 
 UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
     : key(k), uid(find_uid(k, idx))
 {
 
 }
 
 Key UserID::parent() const
 {
     return Key(key);
 }
 
 UserID::Signature UserID::signature(unsigned int index) const
 {
     return Signature(key, uid, index);
 }
 
 unsigned int UserID::numSignatures() const
 {
     if (!uid) {
         return 0;
     }
     unsigned int count = 0;
     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
         ++count;
     }
     return count;
 }
 
 std::vector<UserID::Signature> UserID::signatures() const
 {
     if (!uid) {
         return std::vector<Signature>();
     }
 
     std::vector<Signature> v;
     v.reserve(numSignatures());
     for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
         v.push_back(Signature(key, uid, sig));
     }
     return v;
 }
 
 const char *UserID::id() const
 {
     return uid ? uid->uid : nullptr ;
 }
 
 const char *UserID::name() const
 {
     return uid ? uid->name : nullptr ;
 }
 
 const char *UserID::email() const
 {
     return uid ? uid->email : nullptr ;
 }
 
 const char *UserID::comment() const
 {
     return uid ? uid->comment : nullptr ;
 }
 
 const char *UserID::uidhash() const
 {
     return uid ? uid->uidhash : nullptr ;
 }
 
 UserID::Validity UserID::validity() const
 {
     if (!uid) {
         return Unknown;
     }
     switch (uid->validity) {
     default:
     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
     case GPGME_VALIDITY_UNDEFINED: return Undefined;
     case GPGME_VALIDITY_NEVER:     return Never;
     case GPGME_VALIDITY_MARGINAL:  return Marginal;
     case GPGME_VALIDITY_FULL:      return Full;
     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
     }
 }
 
 char UserID::validityAsString() const
 {
     if (!uid) {
         return '?';
     }
     switch (uid->validity) {
     default:
     case GPGME_VALIDITY_UNKNOWN:   return '?';
     case GPGME_VALIDITY_UNDEFINED: return 'q';
     case GPGME_VALIDITY_NEVER:     return 'n';
     case GPGME_VALIDITY_MARGINAL:  return 'm';
     case GPGME_VALIDITY_FULL:      return 'f';
     case GPGME_VALIDITY_ULTIMATE:  return 'u';
     }
 }
 
 bool UserID::isRevoked() const
 {
     return uid && uid->revoked;
 }
 
 bool UserID::isInvalid() const
 {
     return uid && uid->invalid;
 }
 
 TofuInfo UserID::tofuInfo() const
 {
     if (!uid) {
         return TofuInfo();
     }
     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 (key->protocol != GPGME_PROTOCOL_OpenPGP) {
         return nullptr;
     }
 
     if (!(key->keylist_mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) ||
         !(key->keylist_mode & 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;
 }
 
 std::vector<std::string> UserID::remarks(std::vector<Key> keys, Error &err) const
 {
     std::vector<std::string> ret;
 
     for (const auto &key: keys) {
         const char *rem = remark(key, err);
         if (err) {
             return ret;
         }
         if (rem) {
             ret.push_back(rem);
         }
     }
     return ret;
 }
 
 //
 //
 // class Signature
 //
 //
 
 static gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
 {
     if (uid) {
         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
             if (idx == 0) {
                 return s;
             }
         }
     }
     return nullptr;
 }
 
 static gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
 {
     if (uid) {
         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
             if (s == sig) {
                 return sig;
             }
         }
     }
     return nullptr;
 }
 
 static int signature_index(gpgme_user_id_t uid, gpgme_key_sig_t sig)
 {
     if (uid) {
         int i = 0;
         for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, ++i) {
             if (s == sig) {
                 return i;
             }
         }
     }
     return -1;
 }
 
 UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
 
 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
     : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
 {
 }
 
 UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
     : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
 {
 }
 
 bool UserID::Signature::operator<(const Signature &other)
 {
     // kept for binary compatibility
     return static_cast<const UserID::Signature *>(this)->operator<(other);
 }
 
 bool UserID::Signature::operator<(const Signature &other) const
 {
     // based on cmp_signodes() in g10/keylist.c
 
     // both signatures must belong to the same user ID
     assert(uid == other.uid);
 
     // self-signatures are ordered first
     const char *primaryKeyId = parent().parent().keyID();
     const bool thisIsSelfSignature = strcmp(signerKeyID(), primaryKeyId) == 0;
     const bool otherIsSelfSignature = strcmp(other.signerKeyID(), primaryKeyId) == 0;
     if (thisIsSelfSignature && !otherIsSelfSignature) {
         return true;
     }
     if (otherIsSelfSignature && !thisIsSelfSignature) {
         return false;
     }
 
     // then sort by signer key ID (which are or course the same for self-sigs)
     const int keyIdComparison = strcmp(signerKeyID(), other.signerKeyID());
     if (keyIdComparison < 0) {
         return true;
     }
     if (keyIdComparison > 0) {
         return false;
     }
 
     // followed by creation time
     if (creationTime() < other.creationTime()) {
         return true;
     }
     if (creationTime() > other.creationTime()) {
         return false;
     }
 
     // followed by the class in a way that a rev comes first
     if (certClass() < other.certClass()) {
         return true;
     }
     if (certClass() > other.certClass()) {
         return false;
     }
 
     // to make the sort stable we compare the indexes of the signatures as last resort
     return signature_index(uid, sig) < signature_index(uid, other.sig);
 }
 
 UserID UserID::Signature::parent() const
 {
     return UserID(key, uid);
 }
 
 const char *UserID::Signature::signerKeyID() const
 {
     return sig ? sig->keyid : nullptr ;
 }
 
 const char *UserID::Signature::algorithmAsString() const
 {
     return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
 }
 
 unsigned int UserID::Signature::algorithm() const
 {
     return sig ? sig->pubkey_algo : 0 ;
 }
 
 time_t UserID::Signature::creationTime() const
 {
     return static_cast<time_t>(sig ? sig->timestamp : 0);
 }
 
 time_t UserID::Signature::expirationTime() const
 {
     return static_cast<time_t>(sig ? sig->expires : 0);
 }
 
 bool UserID::Signature::neverExpires() const
 {
     return expirationTime() == time_t(0);
 }
 
 bool UserID::Signature::isRevokation() const
 {
     return sig && sig->revoked;
 }
 
 bool UserID::Signature::isInvalid() const
 {
     return sig && sig->invalid;
 }
 
 bool UserID::Signature::isExpired() const
 {
     return sig && sig->expired;
 }
 
 bool UserID::Signature::isExportable() const
 {
     return sig && sig->exportable;
 }
 
 const char *UserID::Signature::signerUserID() const
 {
     return sig ? sig->uid : nullptr ;
 }
 
 const char *UserID::Signature::signerName() const
 {
     return sig ? sig->name : nullptr ;
 }
 
 const char *UserID::Signature::signerEmail() const
 {
     return sig ? sig->email : nullptr ;
 }
 
 const char *UserID::Signature::signerComment() const
 {
     return sig ? sig->comment : nullptr ;
 }
 
 unsigned int UserID::Signature::certClass() const
 {
     return sig ? sig->sig_class : 0 ;
 }
 
 UserID::Signature::Status UserID::Signature::status() const
 {
     if (!sig) {
         return GeneralError;
     }
 
     switch (gpgme_err_code(sig->status)) {
     case GPG_ERR_NO_ERROR:      return NoError;
     case GPG_ERR_SIG_EXPIRED:   return SigExpired;
     case GPG_ERR_KEY_EXPIRED:   return KeyExpired;
     case GPG_ERR_BAD_SIGNATURE: return BadSignature;
     case GPG_ERR_NO_PUBKEY:     return NoPublicKey;
     default:
     case GPG_ERR_GENERAL:       return GeneralError;
     }
 }
 
 std::string UserID::Signature::statusAsString() const
 {
     if (!sig) {
         return std::string();
     }
     char buf[ 1024 ];
     gpgme_strerror_r(sig->status, buf, sizeof buf);
     buf[ sizeof buf - 1 ] = '\0';
     return std::string(buf);
 }
 
 GpgME::Notation UserID::Signature::notation(unsigned int idx) const
 {
     if (!sig) {
         return GpgME::Notation();
     }
     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
         if (nota->name) {
             if (idx-- == 0) {
                 return GpgME::Notation(nota);
             }
         }
     }
     return GpgME::Notation();
 }
 
 unsigned int UserID::Signature::numNotations() const
 {
     if (!sig) {
         return 0;
     }
     unsigned int count = 0;
     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
         if (nota->name) {
             ++count; // others are policy URLs...
         }
     }
     return count;
 }
 
 std::vector<Notation> UserID::Signature::notations() const
 {
     if (!sig) {
         return std::vector<GpgME::Notation>();
     }
     std::vector<GpgME::Notation> v;
     v.reserve(numNotations());
     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
         if (nota->name) {
             v.push_back(GpgME::Notation(nota));
         }
     }
     return v;
 }
 
 const char *UserID::Signature::policyURL() const
 {
     if (!sig) {
         return nullptr;
     }
     for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
         if (!nota->name) {
             return nota->value;
         }
     }
     return nullptr;
 }
 
 bool UserID::Signature::isTrustSignature() const
 {
     return sig && sig->trust_depth > 0;
 }
 
 TrustSignatureTrust UserID::Signature::trustValue() const
 {
     if (!sig || !isTrustSignature()) {
         return TrustSignatureTrust::None;
     }
     return sig->trust_value >= 120 ? TrustSignatureTrust::Complete : TrustSignatureTrust::Partial;
 }
 
 unsigned int UserID::Signature::trustDepth() const
 {
     return sig ? sig->trust_depth : 0;
 }
 
 const char *UserID::Signature::trustScope() const
 {
     return sig ? sig->trust_scope : nullptr;
 }
 
 std::string UserID::addrSpecFromString(const char *userid)
 {
     if (!userid) {
         return std::string();
     }
     char *normalized = gpgme_addrspec_from_uid (userid);
     if (normalized) {
         std::string ret(normalized);
         gpgme_free(normalized);
         return ret;
     }
     return std::string();
 }
 
 std::string UserID::addrSpec() const
 {
     if (!uid || !uid->address) {
         return std::string();
     }
 
     return uid->address;
 }
 
 Error UserID::revoke()
 {
     if (isNull()) {
         return Error::fromCode(GPG_ERR_GENERAL);
     }
     auto ctx = Context::createForProtocol(parent().protocol());
     if (!ctx) {
         return Error::fromCode(GPG_ERR_INV_ENGINE);
     }
     Error ret = ctx->revUid(key, id());
     delete ctx;
     return ret;
 }
 
 static Key::Origin gpgme_origin_to_pp_origin (const unsigned int origin)
 {
     switch (origin) {
         case GPGME_KEYORG_KS:
             return Key::OriginKS;
         case GPGME_KEYORG_DANE:
             return Key::OriginDane;
         case GPGME_KEYORG_WKD:
             return Key::OriginWKD;
         case GPGME_KEYORG_URL:
             return Key::OriginURL;
         case GPGME_KEYORG_FILE:
             return Key::OriginFile;
         case GPGME_KEYORG_SELF:
             return Key::OriginSelf;
         case GPGME_KEYORG_OTHER:
             return Key::OriginOther;
         case GPGME_KEYORG_UNKNOWN:
         default:
             return Key::OriginUnknown;
     }
 }
 
 Key::Origin UserID::origin() const
 {
     if (isNull()) {
         return Key::OriginUnknown;
     }
     return gpgme_origin_to_pp_origin(uid->origin);
 }
 
 time_t UserID::lastUpdate() const
 {
     return static_cast<time_t>(uid ? uid->last_update : 0);
 }
 
 Error Key::addUid(const char *uid)
 {
     if (isNull()) {
         return Error::fromCode(GPG_ERR_GENERAL);
     }
     auto ctx = Context::createForProtocol(protocol());
     if (!ctx) {
         return Error::fromCode(GPG_ERR_INV_ENGINE);
     }
     Error ret = ctx->addUid(key, uid);
     delete ctx;
     return ret;
 }
 
 Key::Origin Key::origin() const
 {
     if (isNull()) {
         return OriginUnknown;
     }
     return gpgme_origin_to_pp_origin(key->origin);
 }
 
 time_t Key::lastUpdate() const
 {
     return static_cast<time_t>(key ? key->last_update : 0);
 }
 
 bool Key::isBad() const
 {
     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
 }
 
 bool Subkey::isBad() const
 {
     return isNull() || isRevoked() || isExpired() || isDisabled() || isInvalid();
 }
 
 bool UserID::isBad() const
 {
     return isNull() || isRevoked() || isInvalid();
 }
 
 bool UserID::Signature::isBad() const
 {
     return isNull() || isExpired() || isInvalid();
 }
 
 std::ostream &operator<<(std::ostream &os, const UserID &uid)
 {
     os << "GpgME::UserID(";
     if (!uid.isNull()) {
         os << "\n name:      " << protect(uid.name())
            << "\n email:     " << protect(uid.email())
            << "\n mbox:      " << uid.addrSpec()
            << "\n comment:   " << protect(uid.comment())
            << "\n validity:  " << uid.validityAsString()
            << "\n revoked:   " << uid.isRevoked()
            << "\n invalid:   " << uid.isInvalid()
            << "\n numsigs:   " << uid.numSignatures()
            << "\n origin:    " << uid.origin()
            << "\n updated:   " << uid.lastUpdate()
            << "\n tofuinfo:\n" << uid.tofuInfo();
     }
     return os << ')';
 }
 
 std::ostream &operator<<(std::ostream &os, const Subkey &subkey)
 {
     os << "GpgME::Subkey(";
     if (!subkey.isNull()) {
         os << "\n fingerprint:   " << protect(subkey.fingerprint())
            << "\n keyGrip:       " << protect(subkey.keyGrip())
            << "\n creationTime:  " << subkey.creationTime()
            << "\n expirationTime:" << subkey.expirationTime()
            << "\n isRevoked:     " << subkey.isRevoked()
            << "\n isExpired:     " << subkey.isExpired()
            << "\n isInvalid:     " << subkey.isInvalid()
            << "\n isDisabled:    " << subkey.isDisabled()
            << "\n canSign:       " << subkey.canSign()
            << "\n canEncrypt:    " << subkey.canEncrypt()
            << "\n canCertify:    " << subkey.canCertify()
            << "\n canAuth:       " << subkey.canAuthenticate()
            << "\n canRenc:       " << subkey.canRenc()
            << "\n canTimestanp:  " << subkey.canTimestamp()
            << "\n isSecret:      " << subkey.isSecret()
            << "\n isGroupOwned:  " << subkey.isGroupOwned()
            << "\n isQualified:   " << subkey.isQualified()
            << "\n isDeVs:        " << subkey.isDeVs()
            << "\n isCardKey:     " << subkey.isCardKey()
            << "\n cardSerialNumber:" << protect(subkey.cardSerialNumber());
     }
     return os << ')';
 }
 
 std::ostream &operator<<(std::ostream &os, const Key &key)
 {
     os << "GpgME::Key(";
     if (!key.isNull()) {
         os << "\n protocol:   " << protect(key.protocolAsString())
            << "\n ownertrust: " << key.ownerTrustAsString()
            << "\n issuer:     " << protect(key.issuerName())
            << "\n fingerprint:" << protect(key.primaryFingerprint())
            << "\n listmode:   " << key.keyListMode()
-           << "\n canSign:    " << key.canReallySign()
+           << "\n canSign:    " << key.canSign()
            << "\n canEncrypt: " << key.canEncrypt()
            << "\n canCertify: " << key.canCertify()
            << "\n canAuth:    " << key.canAuthenticate()
            << "\n origin:     " << key.origin()
            << "\n updated:    " << key.lastUpdate()
            << "\n uids:\n";
         const std::vector<UserID> uids = key.userIDs();
         std::copy(uids.begin(), uids.end(),
                   std::ostream_iterator<UserID>(os, "\n"));
         const std::vector<Subkey> subkeys = key.subkeys();
         std::copy(subkeys.begin(), subkeys.end(),
                   std::ostream_iterator<Subkey>(os, "\n"));
     }
     return os << ')';
 }
 
 } // namespace GpgME
diff --git a/src/key.h b/src/key.h
index 787cb43e..9e827f63 100644
--- a/src/key.h
+++ b/src/key.h
@@ -1,557 +1,549 @@
 /*
   key.h - wraps a gpgme key
   Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
 
   This file is part of GPGME++.
 
   GPGME++ is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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 Library General Public License for more details.
 
   You should have received a copy of the GNU Library General Public License
   along with GPGME++; see the file COPYING.LIB.  If not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
 */
 
 // -*- c++ -*-
 #ifndef __GPGMEPP_KEY_H__
 #define __GPGMEPP_KEY_H__
 
 #include "global.h"
 #include "notation.h"
 
 #include "gpgmefw.h"
 
 #include <memory>
 #include <sys/time.h>
 
 #include <vector>
 #include <algorithm>
 #include <string>
 
 namespace GpgME
 {
 
 class Context;
 
 class Subkey;
 class UserID;
 class TofuInfo;
 
 typedef std::shared_ptr< std::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
 
 enum class TrustSignatureTrust : char {
     None = 0,
     Partial,
     Complete,
 };
 
 //
 // class Key
 //
 
 class GPGMEPP_EXPORT Key
 {
     friend class ::GpgME::Context;
     struct Null {
 		Null() {}
 	};
 public:
     Key();
     /* implicit */ Key(const Null &);
     Key(const shared_gpgme_key_t &key);
     Key(gpgme_key_t key, bool acquireRef);
 
     static const Null null;
 
     Key(const Key &other) = default;
     const Key &operator=(Key other)
     {
         swap(other);
         return *this;
     }
 
     const Key &mergeWith(const Key &other);
 
     void swap(Key &other)
     {
         using std::swap;
         swap(this->key, other.key);
     }
 
     bool isNull() const
     {
         return !key;
     }
 
     UserID userID(unsigned int index) const;
     Subkey subkey(unsigned int index) const;
 
     unsigned int numUserIDs() const;
     unsigned int numSubkeys() const;
 
     std::vector<UserID> userIDs() const;
     std::vector<Subkey> subkeys() const;
 
     bool isRevoked() const;
     bool isExpired() const;
     bool isDisabled() const;
     bool isInvalid() const;
 
     /*! Shorthand for isNull || isRevoked || isExpired ||
      *                          isDisabled || isInvalid */
     bool isBad() const;
 
     bool canEncrypt() const;
-    /*!
-      This function contains a workaround for old gpgme's: all secret
-      OpenPGP keys canSign() == true, which canReallySign() doesn't
-      have. I don't have time to find what breaks when I remove this
-      workaround, but since Kleopatra merges secret into public keys,
-      the workaround is not necessary there (and actively harms), I've
-      added a new function instead.
-     */
     bool canSign() const;
-    bool canReallySign() const;
+    GPGMEPP_DEPRECATED bool canReallySign() const;
     bool canCertify() const;
     bool canAuthenticate() const;
     bool isQualified() const;
     bool isDeVs() const;
 
     bool hasSecret() const;
     GPGMEPP_DEPRECATED bool isSecret() const
     {
         return hasSecret();
     }
 
     /*!
       @return true if this is a X.509 root certificate (currently
       equivalent to something like
       strcmp( chainID(), subkey(0).fingerprint() ) == 0 )
     */
     bool isRoot() const;
 
     enum OwnerTrust { Unknown = 0, Undefined = 1, Never = 2,
                       Marginal = 3, Full = 4, Ultimate = 5
                     };
 
     OwnerTrust ownerTrust() const;
     char ownerTrustAsString() const;
 
     Protocol protocol() const;
     const char *protocolAsString() const;
 
     const char *issuerSerial() const;
     const char *issuerName() const;
     const char *chainID() const;
 
     const char *keyID() const;
     const char *shortKeyID() const;
     const char *primaryFingerprint() const;
 
     unsigned int keyListMode() const;
 
     /*! Update information about this key.
      * Starts a keylisting for this key with validity
      * and tofu information gathering. Blocks for
      * how long the keylisting takes.*/
     void update();
 
     /**
      * @brief Add a user id to this key.
      *
      * Needs gnupg 2.1.13 and the key needs to be updated
      * afterwards to see the new uid.
      *
      * @param uid should be fully formatted and UTF-8 encoded.
      *
      * @returns a possible error.
      **/
     Error addUid(const char *uid);
 
     /**
      * @brief try to locate the best pgp key for a given mailbox.
      *
      * Boils down to gpg --locate-key <mbox>
      * This may take some time if remote sources are also
      * used.
      *
      * @param mbox should be a mail address does not need to be normalized.
      *
      * @returns The best key for a mailbox or a null key.
      */
     static Key locate(const char *mbox);
 
     /* @enum Origin
      * @brief The Origin of the key. */
     enum Origin : unsigned int {
         OriginUnknown = 0,
         OriginKS = 1,
         OriginDane = 3,
         OriginWKD = 4,
         OriginURL = 5,
         OriginFile = 6,
         OriginSelf = 7,
         OriginOther = 31,
     };
     /*! Get the origin of the key.
      *
      * @returns the Origin. */
     Origin origin() const;
 
     /*! Get the last update time.
      *
      * @returns the last update time. */
     time_t lastUpdate() const;
 private:
     gpgme_key_t impl() const
     {
         return key.get();
     }
     shared_gpgme_key_t key;
 };
 
 //
 // class Subkey
 //
 
 class GPGMEPP_EXPORT Subkey
 {
 public:
     Subkey();
     Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
     Subkey(const shared_gpgme_key_t &key, unsigned int idx);
 
     Subkey(const Subkey &other) = default;
     const Subkey &operator=(Subkey other)
     {
         swap(other);
         return *this;
     }
 
     void swap(Subkey &other)
     {
         using std::swap;
         swap(this->key, other.key);
         swap(this->subkey, other.subkey);
     }
 
     bool isNull() const
     {
         return !key || !subkey;
     }
 
     Key parent() const;
 
     const char *keyID() const;
     const char *fingerprint() const;
 
     time_t creationTime() const;
     time_t expirationTime() const;
     bool neverExpires() const;
 
     bool isRevoked() const;
     bool isExpired() const;
     bool isInvalid() const;
     bool isDisabled() const;
 
     /*! Shorthand for isNull || isRevoked || isExpired ||
      *                          isDisabled || isInvalid */
     bool isBad() const;
 
     bool canEncrypt() const;
     bool canSign() const;
     bool canCertify() const;
     bool canAuthenticate() const;
     bool canRenc() const;
     bool canTimestamp() const;
     bool isGroupOwned() const;
     bool isQualified() const;
     bool isDeVs() const;
     bool isCardKey() const;
 
     bool isSecret() const;
 
     /** Same as gpgme_pubkey_algo_t */
     enum PubkeyAlgo {
         AlgoUnknown = 0,
         AlgoRSA     = 1,
         AlgoRSA_E   = 2,
         AlgoRSA_S   = 3,
         AlgoELG_E   = 16,
         AlgoDSA     = 17,
         AlgoECC     = 18,
         AlgoELG     = 20,
         AlgoECDSA   = 301,
         AlgoECDH    = 302,
         AlgoEDDSA   = 303,
         AlgoMax     = 1 << 31
     };
 
     PubkeyAlgo publicKeyAlgorithm() const;
 
     /**
       @brief Get the public key algorithm name.
 
       This only works for the pre 2.1 algorithms for ECC NULL is returned.
 
       @returns a statically allocated string with the name of the public
                key algorithm, or NULL if that name is not known.
     */
     const char *publicKeyAlgorithmAsString() const;
 
     /** @brief Same as publicKeyAlgorithmAsString but static. */
     static const char *publicKeyAlgorithmAsString(PubkeyAlgo algo);
 
     /**
        @brief Get the key algo string like GnuPG 2.1 prints it.
 
        This returns combinations of size and algorithm. Like
        bp512 or rsa2048. Misnamed because publicKeyAlgorithmAsString
        already used the older pubkey_algo_name.
        Actually uses gpgme_pubkey_algo_string.
 
        @returns the key algorithm as string. Empty string on error.
     */
     std::string algoName() const;
 
     unsigned int length() const;
 
     const char *cardSerialNumber() const;
 
     const char *keyGrip() const;
 
 private:
     shared_gpgme_key_t key;
     gpgme_sub_key_t subkey;
 };
 
 //
 // class UserID
 //
 
 class GPGMEPP_EXPORT UserID
 {
 public:
     class Signature;
 
     UserID();
     UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
     UserID(const shared_gpgme_key_t &key, unsigned int idx);
 
     UserID(const UserID &other) = default;
     const UserID &operator=(UserID other)
     {
         swap(other);
         return *this;
     }
 
     void swap(UserID &other)
     {
         using std::swap;
         swap(this->key, other.key);
         swap(this->uid, other.uid);
     }
 
     bool isNull() const
     {
         return !key || !uid;
     }
 
     Key parent() const;
 
     unsigned int numSignatures() const;
     Signature signature(unsigned int index) const;
     std::vector<Signature> signatures() const;
 
     const char *id() const;
     const char *name() const;
     const char *email() const;
     const char *comment() const;
     const char *uidhash() const;
 
     enum Validity { Unknown = 0, Undefined = 1, Never = 2,
                     Marginal = 3, Full = 4, Ultimate = 5
                   };
 
     Validity validity() const;
     char validityAsString() const;
 
     bool isRevoked() const;
     bool isInvalid() const;
 
     /*! Shorthand for isNull || isRevoked || isInvalid */
     bool isBad() const;
 
     /** TOFU info for this userid.
      * @returns The TOFU stats or a null TofuInfo.
      */
     GpgME::TofuInfo tofuInfo() const;
 
     /*! Wrapper around gpgme_addrspec_from_uid.
      *
      * The input string should match the format of
      * a user id string.
      *
      * @returns a normalized mail address if found
      * or an empty string. */
     static std::string addrSpecFromString(const char *uid);
 
     /*! Wrapper around gpgme_addrspec_from_uid.
      *
      * @returns a normalized mail address for this userid
      * or an empty string. */
     std::string addrSpec() const;
 
     /*! Revoke the user id.
      *
      * Key needs update afterwards.
      *
      * @returns an error on error.*/
     Error revoke();
 
     /*! Get the origin of the key.
      *
      * @returns the Origin. */
     Key::Origin origin() const;
 
     /*! Get the last update time.
      *
      * @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;
 
     /*! Get multiple remarks made by potentially multiple keys. */
     std::vector <std::string> remarks(std::vector<GpgME::Key> remarkers,
                                       Error &error) const;
 
 private:
     shared_gpgme_key_t key;
     gpgme_user_id_t uid;
 };
 
 //
 // class UserID::Signature
 //
 
 class GPGMEPP_EXPORT UserID::Signature
 {
 public:
     typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
 
     Signature();
     Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
     Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
 
     Signature(const Signature &other) = default;
     const Signature &operator=(Signature other)
     {
         swap(other);
         return *this;
     }
 
     void swap(Signature &other)
     {
         using std::swap;
         swap(this->key, other.key);
         swap(this->uid, other.uid);
         swap(this->sig, other.sig);
     }
 
     /*! Defines a canonical sort order for signatures of the same user ID. */
     bool operator<(const Signature &other) const;
 
     GPGMEPP_DEPRECATED bool operator<(const Signature &other);
 
     bool isNull() const
     {
         return !sig || !uid || !key ;
     }
 
     UserID parent() const;
 
     const char *signerKeyID() const;
 
     const char *algorithmAsString() const;
     unsigned int algorithm() const;
     time_t creationTime() const;
     time_t expirationTime() const;
     bool neverExpires() const;
 
     bool isRevokation() const;
     bool isInvalid() const;
     bool isExpired() const;
     bool isExportable() const;
 
     /*! Shorthand for isNull || isExpired || isInvalid */
     bool isBad() const;
 
     const char *signerUserID() const;
     const char *signerName() const;
     const char *signerEmail() const;
     const char *signerComment() const;
 
     unsigned int certClass() const;
 
     enum Status { NoError = 0, SigExpired, KeyExpired,
                   BadSignature, NoPublicKey, GeneralError
                 };
     Status status() const;
     std::string statusAsString() const;
 
     const char *policyURL() const;
 
     unsigned int numNotations() const;
     GpgME::Notation notation(unsigned int idx) const;
     std::vector<GpgME::Notation> notations() const;
 
     bool isTrustSignature() const;
     TrustSignatureTrust trustValue() const;
     unsigned int trustDepth() const;
     const char *trustScope() const;
 
 private:
     shared_gpgme_key_t key;
     gpgme_user_id_t uid;
     gpgme_key_sig_t sig;
 };
 
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const UserID &uid);
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Subkey &subkey);
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Key &key);
 
 } // namespace GpgME
 
 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Key)
 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Subkey)
 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID)
 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID::Signature)
 
 GPGMEPP_MAKE_STRCMP(ByFingerprint, .primaryFingerprint());
 GPGMEPP_MAKE_STRCMP(ByKeyID, .keyID());
 GPGMEPP_MAKE_STRCMP(ByShortKeyID, .shortKeyID());
 GPGMEPP_MAKE_STRCMP(ByChainID, .chainID());
 
 #endif // __GPGMEPP_KEY_H__