Page MenuHome GnuPG

No OneTemporary

diff --git a/src/kleo/enum.cpp b/src/kleo/enum.cpp
index 1d33e802..55862065 100644
--- a/src/kleo/enum.cpp
+++ b/src/kleo/enum.cpp
@@ -1,324 +1,324 @@
/*
kleo/enum.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "enum.h"
#include "libkleo_debug.h"
#include "models/keycache.h"
#include <functional>
#include <KLocalizedString>
#include <gpgme++/key.h>
#include <gpgme++/tofuinfo.h>
#include <QString>
#include <QEventLoop>
static const struct {
Kleo::CryptoMessageFormat format;
const char *displayName;
const char *configName;
} cryptoMessageFormats[] = {
{
Kleo::InlineOpenPGPFormat,
I18N_NOOP("Inline OpenPGP (deprecated)"),
"inline openpgp"
},
{
Kleo::OpenPGPMIMEFormat,
I18N_NOOP("OpenPGP/MIME"),
"openpgp/mime"
},
{
Kleo::SMIMEFormat,
I18N_NOOP("S/MIME"),
"s/mime"
},
{
Kleo::SMIMEOpaqueFormat,
I18N_NOOP("S/MIME Opaque"),
"s/mime opaque"
},
{
Kleo::AnySMIME,
I18N_NOOP("Any S/MIME"),
"any s/mime"
},
{
Kleo::AnyOpenPGP,
I18N_NOOP("Any OpenPGP"),
"any openpgp"
},
};
static const unsigned int numCryptoMessageFormats
= sizeof cryptoMessageFormats / sizeof * cryptoMessageFormats;
const char *Kleo::cryptoMessageFormatToString(Kleo::CryptoMessageFormat f)
{
if (f == AutoFormat) {
return "auto";
}
for (unsigned int i = 0; i < numCryptoMessageFormats; ++i)
if (f == cryptoMessageFormats[i].format) {
return cryptoMessageFormats[i].configName;
}
return nullptr;
}
QStringList Kleo::cryptoMessageFormatsToStringList(unsigned int f)
{
QStringList result;
for (unsigned int i = 0; i < numCryptoMessageFormats; ++i)
if (f & cryptoMessageFormats[i].format) {
result.push_back(QLatin1String(cryptoMessageFormats[i].configName));
}
return result;
}
QString Kleo::cryptoMessageFormatToLabel(Kleo::CryptoMessageFormat f)
{
if (f == AutoFormat) {
return i18n("Any");
}
for (unsigned int i = 0; i < numCryptoMessageFormats; ++i)
if (f == cryptoMessageFormats[i].format) {
return i18n(cryptoMessageFormats[i].displayName);
}
return QString();
}
Kleo::CryptoMessageFormat Kleo::stringToCryptoMessageFormat(const QString &s)
{
const QString t = s.toLower();
for (unsigned int i = 0; i < numCryptoMessageFormats; ++i)
if (t == QLatin1String(cryptoMessageFormats[i].configName)) {
return cryptoMessageFormats[i].format;
}
return AutoFormat;
}
unsigned int Kleo::stringListToCryptoMessageFormats(const QStringList &sl)
{
unsigned int result = 0;
for (QStringList::const_iterator it = sl.begin(); it != sl.end(); ++it) {
result |= stringToCryptoMessageFormat(*it);
}
return result;
}
// For the config values used below, see also kaddressbook/editors/cryptowidget.cpp
const char *Kleo::encryptionPreferenceToString(EncryptionPreference pref)
{
switch (pref) {
case UnknownPreference:
return nullptr;
case NeverEncrypt:
return "never";
case AlwaysEncrypt:
return "always";
case AlwaysEncryptIfPossible:
return "alwaysIfPossible";
case AlwaysAskForEncryption:
return "askAlways";
case AskWheneverPossible:
return "askWhenPossible";
}
return nullptr; // keep the compiler happy
}
Kleo::EncryptionPreference Kleo::stringToEncryptionPreference(const QString &str)
{
if (str == QLatin1String("never")) {
return NeverEncrypt;
}
if (str == QLatin1String("always")) {
return AlwaysEncrypt;
}
if (str == QLatin1String("alwaysIfPossible")) {
return AlwaysEncryptIfPossible;
}
if (str == QLatin1String("askAlways")) {
return AlwaysAskForEncryption;
}
if (str == QLatin1String("askWhenPossible")) {
return AskWheneverPossible;
}
return UnknownPreference;
}
QString Kleo::encryptionPreferenceToLabel(EncryptionPreference pref)
{
switch (pref) {
case NeverEncrypt:
return i18n("Never Encrypt");
case AlwaysEncrypt:
return i18n("Always Encrypt");
case AlwaysEncryptIfPossible:
return i18n("Always Encrypt If Possible");
case AlwaysAskForEncryption:
return i18n("Ask");
case AskWheneverPossible:
return i18n("Ask Whenever Possible");
default:
return xi18nc("no specific preference", "<placeholder>none</placeholder>");
}
}
const char *Kleo::signingPreferenceToString(SigningPreference pref)
{
switch (pref) {
case UnknownSigningPreference:
return nullptr;
case NeverSign:
return "never";
case AlwaysSign:
return "always";
case AlwaysSignIfPossible:
return "alwaysIfPossible";
case AlwaysAskForSigning:
return "askAlways";
case AskSigningWheneverPossible:
return "askWhenPossible";
}
return nullptr; // keep the compiler happy
}
Kleo::SigningPreference Kleo::stringToSigningPreference(const QString &str)
{
if (str == QLatin1String("never")) {
return NeverSign;
}
if (str == QLatin1String("always")) {
return AlwaysSign;
}
if (str == QLatin1String("alwaysIfPossible")) {
return AlwaysSignIfPossible;
}
if (str == QLatin1String("askAlways")) {
return AlwaysAskForSigning;
}
if (str == QLatin1String("askWhenPossible")) {
return AskSigningWheneverPossible;
}
return UnknownSigningPreference;
}
QString Kleo::signingPreferenceToLabel(SigningPreference pref)
{
switch (pref) {
case NeverSign:
return i18n("Never Sign");
case AlwaysSign:
return i18n("Always Sign");
case AlwaysSignIfPossible:
return i18n("Always Sign If Possible");
case AlwaysAskForSigning:
return i18n("Ask");
case AskSigningWheneverPossible:
return i18n("Ask Whenever Possible");
default:
return i18nc("no specific preference", "<none>");
}
}
Kleo::TrustLevel Kleo::trustLevel(const GpgME::Key &key)
{
TrustLevel maxTl = Level0;
for (int i = 0, c = key.numUserIDs(); i < c; ++i) {
const auto tl = trustLevel(key.userID(i));
maxTl = qMax(maxTl, tl);
if (maxTl == Level4) {
break;
}
}
return maxTl;
}
namespace {
bool hasTrustedSignature(const GpgME::UserID &uid)
{
- // lazily intialized cache
+ // lazily initialized cache
static std::shared_ptr<const Kleo::KeyCache> keyCache;
if (!keyCache) {
keyCache = Kleo::KeyCache::instance();
}
if (!keyCache->initialized()) {
QEventLoop el;
QObject::connect(keyCache.get(), &Kleo::KeyCache::keyListingDone,
&el, &QEventLoop::quit);
el.exec();
}
const auto signatures = uid.signatures();
std::vector<std::string> sigKeyIDs;
std::transform(signatures.cbegin(), signatures.cend(),
std::back_inserter(sigKeyIDs),
std::bind(&GpgME::UserID::Signature::signerKeyID, std::placeholders::_1));
const auto keys = keyCache->findByKeyIDOrFingerprint(sigKeyIDs);
return std::any_of(keys.cbegin(), keys.cend(),
[](const GpgME::Key &key) {
return key.ownerTrust() == GpgME::Key::Ultimate;
});
}
}
Kleo::TrustLevel Kleo::trustLevel(const GpgME::UserID &uid)
{
// Modelled after https://wiki.gnupg.org/EasyGpg2016/AutomatedEncryption,
// but modified to cover all cases, unlike the pseudocode in the document.
//
// TODO: Check whether the key comes from a trusted source (Cert/PKA/DANE/WKD)
switch (uid.validity()) {
case GpgME::UserID::Unknown:
case GpgME::UserID::Undefined:
case GpgME::UserID::Never:
// Not enough trust -> level 0
return Level0;
case GpgME::UserID::Marginal:
// Marginal trust without TOFU data means the key is still trusted
// through the Web of Trust -> level 2
if (uid.tofuInfo().isNull()) {
return Level2;
}
// Marginal trust with TOFU, level will depend on TOFU history
switch (uid.tofuInfo().validity()) {
case GpgME::TofuInfo::ValidityUnknown:
case GpgME::TofuInfo::Conflict:
case GpgME::TofuInfo::NoHistory:
// Marginal trust, but not enough history -> level 0
return Level0;
case GpgME::TofuInfo::LittleHistory:
// Marginal trust, but too little history -> level 1
return Level1;
case GpgME::TofuInfo::BasicHistory:
case GpgME::TofuInfo::LargeHistory:
// Marginal trust and enough history -> level 2
return Level2;
}
return Level2; // Not reached, but avoids fallthrough warnings
case GpgME::UserID::Full:
// Full trust, trust level depends whether the UserID is signed with
// at least one key with Ultimate ownertrust.
return hasTrustedSignature(uid) ? Level4 : Level3;
case GpgME::UserID::Ultimate:
// Ultimate trust -> leve 4
return Level4;
}
Q_UNREACHABLE();
}
diff --git a/src/kleo/keyresolver.h b/src/kleo/keyresolver.h
index fced9cc2..639b4df3 100644
--- a/src/kleo/keyresolver.h
+++ b/src/kleo/keyresolver.h
@@ -1,187 +1,187 @@
/* -*- c++ -*-
keyresolver.h
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QMap>
#include <QObject>
#include <QString>
#include <gpgme++/global.h>
#include <memory>
#include <vector>
#include "kleo_export.h"
class QStringList;
namespace GpgME
{
class Key;
}
namespace Kleo
{
/**
* Class to find Keys for E-Mail signing and encryption.
*
* The KeyResolver uses the Keycache to find keys for signing
* or encryption.
*
* Overrides can be provided for address book integration.
*
* If no override key(s) are provided for an address and no
* KeyGroup for this address is found, then the key
* with a uid that matches the address and has the highest
* validity is used. If both keys have the same validity,
* then the key with the newest subkey is used.
*
* The KeyResolver also supports groups so the number of
* encryption keys does not necessarily
* need to match the amount of sender addresses. For this reason
* maps are used to map addresses to lists of keys.
*
* The keys can be OpenPGP keys and S/MIME (CMS) keys.
* As a caller you need to partition the keys by their protocol and
* send one message for each protocol for the recipients and signed
* by the signing keys.
*/
class KLEO_EXPORT KeyResolver : public QObject
{
Q_OBJECT
public:
/**
* Solution represents the solution found by the KeyResolver.
* @a protocol hints at the protocol of the signing and encryption keys,
* i.e. if @a protocol is either @c GpgME::OpenPGP or @c GpgME::CMS, then
* all keys have the corresponding protocol. Otherwise, the keys have
* mixed protocols.
* @a signingKeys contains the signing keys to use. It contains
* zero or one OpenPGP key and zero or one S/MIME key.
* @a encryptionKeys contains the encryption keys to use for the
* different recipients. The keys of the map represent the normalized
* email addresses of the recipients.
*/
struct Solution
{
GpgME::Protocol protocol = GpgME::UnknownProtocol;
std::vector<GpgME::Key> signingKeys;
QMap<QString, std::vector<GpgME::Key>> encryptionKeys;
};
/** Creates a new key resolver object.
*
* @param encrypt: Should encryption keys be selected.
* @param sign: Should signing keys be selected.
* @param protocol: A specific key protocol (OpenPGP, S/MIME) for selection. Default: Both protocols.
* @param allowMixed: Specify if multiple message formats may be resolved.
**/
explicit KeyResolver(bool encrypt, bool sign,
GpgME::Protocol protocol = GpgME::UnknownProtocol,
bool allowMixed = true);
~KeyResolver() override;
/**
* Set the list of recipient addresses.
*
* @param addresses: A list of (not necessarily normalized) email addresses
*/
void setRecipients(const QStringList &addresses);
/**
* Set the sender's address.
*
* This address is added to the list of recipients (for encryption to self)
* and it is used for signing key resolution, if the signing keys are not
* explicitly set through setSigningKeys.
*
* @param sender: The sender of this message.
*/
void setSender(const QString &sender);
/**
* Set up possible override keys for recipients addresses.
* The keys for the fingerprints are looked
* up and used when found.
*
* Overrides for @c GpgME::UnknownProtocol are used regardless of the
* protocol. Overrides for a specific protocol are only used for this
- * protocol. Overrides for @c GpgME::UnknownProtocol takes precendent over
+ * protocol. Overrides for @c GpgME::UnknownProtocol takes precedence over
* overrides for a specific protocol.
*
* @param overrides: A map of \<protocol\> -> (\<address\> \<fingerprints\>)
*/
void setOverrideKeys(const QMap<GpgME::Protocol, QMap<QString, QStringList> > &overrides);
/**
* Set explicit signing keys to use.
*/
void setSigningKeys(const QStringList &fingerprints);
/**
* Set the minimum user id validity for autoresolution.
*
* The default value is marginal
*
* @param validity int representation of a GpgME::UserID::Validity.
*/
void setMinimumValidity(int validity);
/**
* Get the result of the resolution.
*
* @return the resolved keys for signing and encryption.
*/
Solution result() const;
/**
* Starts the key resolving procedure. Emits keysResolved on success or
* error.
*
* @param showApproval: If set to true a dialog listing the keys
* will always be shown.
* @param parentWidget: Optional, a Widget to use as parent for dialogs.
*/
void start(bool showApproval, QWidget *parentWidget = nullptr);
/**
* Set window flags for a possible dialog.
*/
void setDialogWindowFlags(Qt::WindowFlags flags);
/**
* Set the protocol that is preferred to be displayed first when
* it is not clear from the keys. E.g. if both OpenPGP and S/MIME
* can be resolved.
*/
void setPreferredProtocol(GpgME::Protocol proto);
Q_SIGNALS:
/**
* Emitted when key resolution finished.
*
* @param success: The general result. If true continue sending,
* if false abort.
* @param sendUnencrypted: If there could be no key found for one of
* the recipients the user was queried if the
* mail should be sent out unencrypted.
* sendUnencrypted is true if the user agreed
* to this.*/
void keysResolved(bool success, bool sendUnencrypted);
private:
class Private;
std::unique_ptr<Private> d;
};
} // namespace Kleo
diff --git a/src/models/useridlistmodel.cpp b/src/models/useridlistmodel.cpp
index 89d9f908..f5312d29 100644
--- a/src/models/useridlistmodel.cpp
+++ b/src/models/useridlistmodel.cpp
@@ -1,360 +1,360 @@
/* -*- mode: c++; c-basic-offset:4 -*-
models/useridlistmodel.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Andre Heinecke <aheinecke@gnupg.org>
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-libkleo.h>
#include "useridlistmodel.h"
#include "keycache.h"
#include "utils/formatting.h"
#include <KLocalizedString>
#include <QVariant>
#include <QIcon>
#include <gpgme++/key.h>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_REMARKS
#endif
#if GPGMEPP_VERSION >= 0x10E01 // 1.14.1
# define GPGME_USERID_SIGNATURES_ARE_SORTABLE
#endif
using namespace GpgME;
using namespace Kleo;
class UIDModelItem
{
// A uid model item can either be a UserID::Signature or a UserID.
// you can find out which it is if the uid or the signature return
// null values. (Not null but isNull)
//
public:
explicit UIDModelItem(const UserID::Signature &sig, UIDModelItem *parentItem, bool showRemarks)
: mParentItem{parentItem}
, mSig{sig}
{
mItemData << QString::fromUtf8(sig.signerKeyID())
<< Formatting::prettyName(sig)
<< Formatting::prettyEMail(sig)
<< Formatting::creationDateString(sig)
<< Formatting::expirationDateString(sig)
<< Formatting::validityShort(sig)
<< (sig.isExportable() ? QStringLiteral("✓") : QString());
QString lastNotation;
if (showRemarks && parentItem) {
for (const auto &notation: sig.notations()) {
if (notation.name() && !strcmp(notation.name(), "rem@gnupg.org")) {
lastNotation = QString::fromUtf8(notation.value());
}
}
}
mItemData << lastNotation;
#ifdef GPGMEPP_SUPPORTS_TRUST_SIGNATURES
mItemData << Formatting::trustSignatureDomain(sig);
#endif
}
explicit UIDModelItem(const UserID &uid, UIDModelItem *parentItem)
: mParentItem{parentItem}
, mUid{uid}
{
mItemData << Formatting::prettyUserID(uid);
}
// The root item
UIDModelItem()
{
mItemData << i18n("ID")
<< i18n("Name")
<< i18n("E-Mail")
<< i18n("Valid From")
<< i18n("Valid Until")
<< i18n("Status")
<< i18n("Exportable")
<< i18n("Tags");
#ifdef GPGMEPP_SUPPORTS_TRUST_SIGNATURES
mItemData << i18n("Trust Signature For");
#endif
}
~UIDModelItem()
{
qDeleteAll(mChildItems);
}
void appendChild(UIDModelItem *child)
{
mChildItems << child;
}
UIDModelItem *child(int row) const
{
return mChildItems.value(row);
}
const UIDModelItem *constChild(int row) const
{
return mChildItems.value(row);
}
int childCount() const
{
return mChildItems.count();
}
int columnCount() const
{
if (childCount()) {
// We take the value from the first child
// as we are likely a UID and our children
// are UID Signatures.
return constChild(0)->columnCount();
}
return mItemData.count();
}
QVariant data(int column) const
{
return mItemData.value(column);
}
QVariant toolTip(int column) const
{
if (!mSig.isNull()) {
if (column == static_cast<int>(UserIDListModel::Column::Status)) {
return i18n("class %1", mSig.certClass());
} else if (column == static_cast<int>(UserIDListModel::Column::TrustSignatureDomain)) {
return Formatting::trustSignature(mSig);
}
}
return mItemData.value(column);
}
QVariant icon(int column) const
{
if (!mSig.isNull() && column == static_cast<int>(UserIDListModel::Column::Status)) {
return Formatting::validityIcon(mSig);
}
return {};
}
int row() const
{
if (mParentItem) {
return mParentItem->mChildItems.indexOf(const_cast<UIDModelItem*>(this));
}
return 0;
}
UIDModelItem *parentItem() const
{
return mParentItem;
}
UserID::Signature signature() const
{
return mSig;
}
UserID uid() const
{
return mUid;
}
private:
QList<UIDModelItem*> mChildItems;
QList<QVariant> mItemData;
UIDModelItem *mParentItem = nullptr;
UserID::Signature mSig;
UserID mUid;
};
UserIDListModel::UserIDListModel(QObject *p)
: QAbstractItemModel{p}
{
}
UserIDListModel::~UserIDListModel() = default;
Key UserIDListModel::key() const
{
return mKey;
}
void UserIDListModel::setKey(const Key &key)
{
beginResetModel();
mKey = key;
mRootItem.reset(new UIDModelItem);
for (int i = 0, ids = key.numUserIDs(); i < ids; ++i) {
UserID uid = key.userID(i);
auto uidItem = new UIDModelItem(uid, mRootItem.get());
mRootItem->appendChild(uidItem);
std::vector<UserID::Signature> sigs = uid.signatures();
#ifdef GPGME_USERID_SIGNATURES_ARE_SORTABLE
std::sort(sigs.begin(), sigs.end());
#endif
for (const auto &sig : sigs) {
auto sigItem = new UIDModelItem(sig, uidItem, mRemarksEnabled);
uidItem->appendChild(sigItem);
}
}
endResetModel();
}
int UserIDListModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return static_cast<UIDModelItem*>(parent.internalPointer())->columnCount();
}
if (!mRootItem) {
return 0;
}
return mRootItem->columnCount();
}
int UserIDListModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0 || !mRootItem) {
return 0;
}
const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem*>(parent.internalPointer());
return parentItem->childCount();
}
QModelIndex UserIDListModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent)) {
return {};
}
const UIDModelItem *const parentItem = !parent.isValid() ? mRootItem.get() : static_cast<UIDModelItem*>(parent.internalPointer());
UIDModelItem *const childItem = parentItem->child(row);
if (childItem) {
return createIndex(row, column, childItem);
} else {
return QModelIndex();
}
}
QModelIndex UserIDListModel::parent(const QModelIndex &index) const
{
if (!index.isValid()) {
return {};
}
auto childItem = static_cast<UIDModelItem*>(index.internalPointer());
UIDModelItem *parentItem = childItem->parentItem();
if (parentItem == mRootItem.get()) {
return QModelIndex();
}
return createIndex(parentItem->row(), 0, parentItem);
}
QVariant UserIDListModel::headerData(int section, Qt::Orientation o, int role) const
{
if (o == Qt::Horizontal && mRootItem) {
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
return mRootItem->data(section);
}
}
return QVariant();
}
QVariant UserIDListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole &&
role != Qt::DecorationRole) {
return QVariant();
}
auto item = static_cast<UIDModelItem*>(index.internalPointer());
if (role == Qt::ToolTipRole) {
return item->toolTip(index.column());
}
if (role == Qt::DecorationRole) {
return item->icon(index.column());
}
return item->data(index.column());
}
UserID UserIDListModel::userID(const QModelIndex& index) const
{
if (!index.isValid()) {
return UserID();
}
UIDModelItem *item = static_cast<UIDModelItem*>(index.internalPointer());
return item->uid();
}
-QVector<UserID> UserIDListModel::userIDs(const QModelIndexList &indexs) const
+QVector<UserID> UserIDListModel::userIDs(const QModelIndexList &indexes) const
{
QVector<GpgME::UserID> ret;
- for (const QModelIndex &idx : indexs) {
+ for (const QModelIndex &idx : indexes) {
if (!idx.isValid()) {
continue;
}
auto item = static_cast<UIDModelItem*>(idx.internalPointer());
if (!item->uid().isNull()) {
ret << item->uid();
}
}
return ret;
}
UserID::Signature UserIDListModel::signature(const QModelIndex& index) const
{
if (!index.isValid()) {
return UserID::Signature();
}
UIDModelItem *item = static_cast<UIDModelItem*>(index.internalPointer());
return item->signature();
}
-QVector<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexs) const
+QVector<UserID::Signature> UserIDListModel::signatures(const QModelIndexList &indexes) const
{
QVector<GpgME::UserID::Signature> ret;
- for (const QModelIndex &idx : indexs) {
+ for (const QModelIndex &idx : indexes) {
if (!idx.isValid()) {
continue;
}
auto item = static_cast<UIDModelItem*>(idx.internalPointer());
if (!item->signature().isNull()) {
ret << item->signature();
}
}
return ret;
}
void UserIDListModel::enableRemarks(bool value)
{
mRemarksEnabled = value;
}
diff --git a/src/models/useridlistmodel.h b/src/models/useridlistmodel.h
index ca4fc5d2..3a89a9bc 100644
--- a/src/models/useridlistmodel.h
+++ b/src/models/useridlistmodel.h
@@ -1,75 +1,75 @@
/* -*- mode: c++; c-basic-offset:4 -*-
models/useridlistmodel.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2016 Andre Heinecke <aheinecke@gnupg.org>
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <kleo_export.h>
#include <QAbstractItemModel>
#include <gpgme++/key.h> // since Signature is nested in UserID...
#include <memory>
class UIDModelItem;
namespace Kleo
{
class KLEO_EXPORT UserIDListModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum class Column {
Id,
Name,
Email,
ValidFrom,
ValidUntil,
Status,
Exportable,
Tags,
TrustSignatureDomain,
};
explicit UserIDListModel(QObject *parent = nullptr);
~UserIDListModel() override;
GpgME::Key key() const;
public:
GpgME::UserID userID(const QModelIndex &index) const;
- QVector<GpgME::UserID> userIDs(const QModelIndexList &indexs) const;
+ QVector<GpgME::UserID> userIDs(const QModelIndexList &indexes) const;
GpgME::UserID::Signature signature(const QModelIndex &index) const;
- QVector<GpgME::UserID::Signature> signatures(const QModelIndexList &indexs) const;
+ QVector<GpgME::UserID::Signature> signatures(const QModelIndexList &indexes) const;
void enableRemarks(bool value);
public Q_SLOTS:
void setKey(const GpgME::Key &key);
public:
int columnCount(const QModelIndex &pindex = QModelIndex()) const override;
int rowCount(const QModelIndex &pindex = QModelIndex()) const override;
QVariant headerData(int section, Qt::Orientation o, int role = Qt::DisplayRole) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int col, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
private:
GpgME::Key mKey;
bool mRemarksEnabled = false;
std::unique_ptr<UIDModelItem> mRootItem;
};
}
diff --git a/src/ui/keyselectiondialog.cpp b/src/ui/keyselectiondialog.cpp
index 14e4e419..df24a9b0 100644
--- a/src/ui/keyselectiondialog.cpp
+++ b/src/ui/keyselectiondialog.cpp
@@ -1,980 +1,980 @@
/* -*- c++ -*-
keyselectiondialog.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
Based on kpgpui.cpp
SPDX-FileCopyrightText: 2001, 2002 the KPGP authors
See file libkdenetwork/AUTHORS.kpgp for details
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "keyselectiondialog.h"
#include "keylistview.h"
#include "progressdialog.h"
#include "libkleo/dn.h"
#include "kleo_ui_debug.h"
// gpgme++
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include <qgpgme/keylistjob.h>
// KDE
#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSharedConfig>
// Qt
#include <QApplication>
#include <QCheckBox>
#include <QDateTime>
#include <QDialogButtonBox>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QProcess>
#include <QPushButton>
#include <QRegExp>
#include <QScrollBar>
#include <QTimer>
#include <QVBoxLayout>
#include <algorithm>
#include <iterator>
#include <string.h>
static bool checkKeyUsage(const GpgME::Key &key, unsigned int keyUsage, QString *statusString = nullptr)
{
auto setStatusString = [statusString](const QString &status) {
if (statusString) {
*statusString = status;
}
};
if (keyUsage & Kleo::KeySelectionDialog::ValidKeys) {
if (key.isInvalid()) {
if (key.keyListMode() & GpgME::Validate) {
qCDebug(KLEO_UI_LOG) << "key is invalid";
setStatusString(i18n("The key is not valid."));
return false;
} else {
qCDebug(KLEO_UI_LOG) << "key is invalid - ignoring";
}
}
if (key.isExpired()) {
qCDebug(KLEO_UI_LOG) << "key is expired";
setStatusString(i18n("The key is expired."));
return false;
} else if (key.isRevoked()) {
qCDebug(KLEO_UI_LOG) << "key is revoked";
setStatusString(i18n("The key is revoked."));
return false;
} else if (key.isDisabled()) {
qCDebug(KLEO_UI_LOG) << "key is disabled";
setStatusString(i18n("The key is disabled."));
return false;
}
}
if (keyUsage & Kleo::KeySelectionDialog::EncryptionKeys &&
!key.canEncrypt()) {
qCDebug(KLEO_UI_LOG) << "key can't encrypt";
setStatusString(i18n("The key is not designated for encryption."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::SigningKeys &&
!key.canSign()) {
qCDebug(KLEO_UI_LOG) << "key can't sign";
setStatusString(i18n("The key is not designated for signing."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::CertificationKeys &&
!key.canCertify()) {
qCDebug(KLEO_UI_LOG) << "key can't certify";
setStatusString(i18n("The key is not designated for certifying."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::AuthenticationKeys &&
!key.canAuthenticate()) {
qCDebug(KLEO_UI_LOG) << "key can't authenticate";
setStatusString(i18n("The key is not designated for authentication."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::SecretKeys &&
!(keyUsage & Kleo::KeySelectionDialog::PublicKeys) &&
!key.hasSecret()) {
qCDebug(KLEO_UI_LOG) << "key isn't secret";
setStatusString(i18n("The key is not secret."));
return false;
}
if (keyUsage & Kleo::KeySelectionDialog::TrustedKeys &&
key.protocol() == GpgME::OpenPGP &&
// only check this for secret keys for now.
// Seems validity isn't checked for secret keylistings...
!key.hasSecret()) {
std::vector<GpgME::UserID> uids = key.userIDs();
for (std::vector<GpgME::UserID>::const_iterator it = uids.begin(); it != uids.end(); ++it)
if (!it->isRevoked() && it->validity() >= GpgME::UserID::Marginal) {
return true;
}
qCDebug(KLEO_UI_LOG) << "key has no UIDs with validity >= Marginal";
setStatusString(i18n("The key is not trusted enough."));
return false;
}
// X.509 keys are always trusted, else they won't be the keybox.
// PENDING(marc) check that this ^ is correct
setStatusString(i18n("The key can be used."));
return true;
}
static bool checkKeyUsage(const std::vector<GpgME::Key> &keys, unsigned int keyUsage)
{
for (auto it = keys.begin(); it != keys.end(); ++it)
if (!checkKeyUsage(*it, keyUsage)) {
return false;
}
return true;
}
static inline QString time_t2string(time_t t)
{
QDateTime dt;
dt.setTime_t(t);
return dt.toString();
}
namespace
{
class ColumnStrategy : public Kleo::KeyListView::ColumnStrategy
{
public:
ColumnStrategy(unsigned int keyUsage);
QString title(int col) const override;
int width(int col, const QFontMetrics &fm) const override;
QString text(const GpgME::Key &key, int col) const override;
QString toolTip(const GpgME::Key &key, int col) const override;
QIcon icon(const GpgME::Key &key, int col) const override;
private:
const QIcon mKeyGoodPix, mKeyBadPix, mKeyUnknownPix, mKeyValidPix;
const unsigned int mKeyUsage;
};
static QString iconPath(const QString &name)
{
return QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("libkleopatra/pics/") + name + QStringLiteral(".png"));
}
ColumnStrategy::ColumnStrategy(unsigned int keyUsage)
: Kleo::KeyListView::ColumnStrategy(),
mKeyGoodPix(iconPath(QStringLiteral("key_ok"))),
mKeyBadPix(iconPath(QStringLiteral("key_bad"))),
mKeyUnknownPix(iconPath(QStringLiteral("key_unknown"))),
mKeyValidPix(iconPath(QStringLiteral("key"))),
mKeyUsage(keyUsage)
{
if (keyUsage == 0)
qCWarning(KLEO_UI_LOG)
<< "KeySelectionDialog: keyUsage == 0. You want to use AllKeys instead.";
}
QString ColumnStrategy::title(int col) const
{
switch (col) {
case 0: return i18n("Key ID");
case 1: return i18n("User ID");
default: return QString();
}
}
int ColumnStrategy::width(int col, const QFontMetrics &fm) const
{
if (col == 0) {
static const char hexchars[] = "0123456789ABCDEF";
int maxWidth = 0;
for (unsigned int i = 0; i < 16; ++i) {
maxWidth = qMax(fm.boundingRect(QLatin1Char(hexchars[i])).width(), maxWidth);
}
return 8 * maxWidth + 2 * 16 /* KIconLoader::SizeSmall */;
}
return Kleo::KeyListView::ColumnStrategy::width(col, fm);
}
QString ColumnStrategy::text(const GpgME::Key &key, int col) const
{
switch (col) {
case 0: {
if (key.shortKeyID()) {
return QString::fromUtf8(key.shortKeyID());
} else {
return xi18n("<placeholder>unknown</placeholder>");
}
}
case 1: {
const char *uid = key.userID(0).id();
if (key.protocol() == GpgME::OpenPGP) {
return uid && *uid ? QString::fromUtf8(uid) : QString();
} else { // CMS
return Kleo::DN(uid).prettyDN();
}
}
default: return QString();
}
}
QString ColumnStrategy::toolTip(const GpgME::Key &key, int) const
{
const char *uid = key.userID(0).id();
const char *fpr = key.primaryFingerprint();
const char *issuer = key.issuerName();
const GpgME::Subkey subkey = key.subkey(0);
const QString expiry = subkey.neverExpires() ? i18n("never") : time_t2string(subkey.expirationTime());
const QString creation = time_t2string(subkey.creationTime());
QString keyStatusString;
if (!checkKeyUsage(key, mKeyUsage, &keyStatusString)) {
// Show the status in bold if there is a problem
keyStatusString = QLatin1String("<b>") % keyStatusString % QLatin1String("</b>");
}
QString html = QStringLiteral("<qt><p style=\"style='white-space:pre'\">");
if (key.protocol() == GpgME::OpenPGP) {
html += i18n("OpenPGP key for <b>%1</b>", uid ? QString::fromUtf8(uid) : i18n("unknown"));
} else {
html += i18n("S/MIME key for <b>%1</b>", uid ? Kleo::DN(uid).prettyDN() : i18n("unknown"));
}
html += QStringLiteral("</p><table>");
const auto addRow = [&html](const QString &name, const QString &value) {
html += QStringLiteral("<tr><td align=\"right\"><b>%1: </b></td><td>%2</td></tr>").arg(name, value);
};
addRow(i18nc("Key creation date", "Created"), creation);
addRow(i18nc("Key Expiration date", "Expiry"), expiry);
addRow(i18nc("Key fingerprint", "Fingerprint"), fpr ? QString::fromLatin1(fpr) : i18n("unknown"));
if (key.protocol() != GpgME::OpenPGP) {
addRow(i18nc("Key issuer", "Issuer"), issuer ? Kleo::DN(issuer).prettyDN() : i18n("unknown"));
}
addRow(i18nc("Key status", "Status"), keyStatusString);
html += QStringLiteral("</table></qt>");
return html;
}
QIcon ColumnStrategy::icon(const GpgME::Key &key, int col) const
{
if (col != 0) {
return QIcon();
}
// this key did not undergo a validating keylisting yet:
if (!(key.keyListMode() & GpgME::Validate)) {
return mKeyUnknownPix;
}
if (!checkKeyUsage(key, mKeyUsage)) {
return mKeyBadPix;
}
if (key.protocol() == GpgME::CMS) {
return mKeyGoodPix;
}
switch (key.userID(0).validity()) {
default:
case GpgME::UserID::Unknown:
case GpgME::UserID::Undefined:
return mKeyUnknownPix;
case GpgME::UserID::Never:
return mKeyValidPix;
case GpgME::UserID::Marginal:
case GpgME::UserID::Full:
case GpgME::UserID::Ultimate:
return mKeyGoodPix;
}
}
}
static const int sCheckSelectionDelay = 250;
Kleo::KeySelectionDialog::KeySelectionDialog(QWidget *parent, Options options)
: QDialog(parent),
mOpenPGPBackend(QGpgME::openpgp()),
mSMIMEBackend(QGpgME::smime()),
mKeyUsage(AllKeys)
{
qCDebug(KLEO_UI_LOG) << "mTruncated:" << mTruncated << "mSavedOffsetY:" << mSavedOffsetY;
setUpUI(options, QString());
}
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const std::vector<GpgME::Key> &selectedKeys,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mSelectedKeys(selectedKeys),
mKeyUsage(keyUsage)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, QString());
}
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const QString &initialQuery,
const std::vector<GpgME::Key> &selectedKeys,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mSelectedKeys(selectedKeys),
mKeyUsage(keyUsage),
mSearchText(initialQuery),
mInitialQuery(initialQuery)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, initialQuery);
}
Kleo::KeySelectionDialog::KeySelectionDialog(const QString &title,
const QString &text,
const QString &initialQuery,
unsigned int keyUsage,
bool extendedSelection,
bool rememberChoice,
QWidget *parent,
bool modal)
: QDialog(parent),
mKeyUsage(keyUsage),
mSearchText(initialQuery),
mInitialQuery(initialQuery)
{
setWindowTitle(title);
setModal(modal);
init(rememberChoice, extendedSelection, text, initialQuery);
}
void Kleo::KeySelectionDialog::setUpUI(Options options, const QString &initialQuery)
{
auto mainLayout = new QVBoxLayout(this);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
mOkButton = buttonBox->button(QDialogButtonBox::Ok);
mOkButton->setDefault(true);
mOkButton->setShortcut(Qt::CTRL | Qt::Key_Return);
mCheckSelectionTimer = new QTimer(this);
mStartSearchTimer = new QTimer(this);
QFrame *page = new QFrame(this);
mainLayout->addWidget(page);
mainLayout->addWidget(buttonBox);
mTopLayout = new QVBoxLayout(page);
mTopLayout->setContentsMargins(0, 0, 0, 0);
mTextLabel = new QLabel(page);
mTextLabel->setWordWrap(true);
// Setting the size policy is necessary as a workaround for https://issues.kolab.org/issue4429
// and http://bugreports.qt.nokia.com/browse/QTBUG-8740
mTextLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
connect(mTextLabel, &QLabel::linkActivated, this, &KeySelectionDialog::slotStartCertificateManager);
mTopLayout->addWidget(mTextLabel);
mTextLabel->hide();
QPushButton *const searchExternalPB =
new QPushButton(i18n("Search for &External Certificates"), page);
mTopLayout->addWidget(searchExternalPB, 0, Qt::AlignLeft);
connect(searchExternalPB, &QAbstractButton::clicked, this, &KeySelectionDialog::slotStartSearchForExternalCertificates);
if (initialQuery.isEmpty()) {
searchExternalPB->hide();
}
auto hlay = new QHBoxLayout();
mTopLayout->addLayout(hlay);
auto le = new QLineEdit(page);
le->setClearButtonEnabled(true);
le->setText(initialQuery);
QLabel *lbSearchFor = new QLabel(i18n("&Search for:"), page);
lbSearchFor->setBuddy(le);
hlay->addWidget(lbSearchFor);
hlay->addWidget(le, 1);
le->setFocus();
connect(le, &QLineEdit::textChanged,
this, [this] (const QString &s) { slotSearch(s); });
connect(mStartSearchTimer, &QTimer::timeout, this, &KeySelectionDialog::slotFilter);
mKeyListView = new KeyListView(new ColumnStrategy(mKeyUsage), nullptr, page);
mKeyListView->setObjectName(QStringLiteral("mKeyListView"));
mKeyListView->header()->stretchLastSection();
mKeyListView->setRootIsDecorated(true);
mKeyListView->setSortingEnabled(true);
mKeyListView->header()->setSortIndicatorShown(true);
mKeyListView->header()->setSortIndicator(1, Qt::AscendingOrder); // sort by User ID
if (options & ExtendedSelection) {
mKeyListView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
mTopLayout->addWidget(mKeyListView, 10);
if (options & RememberChoice) {
mRememberCB = new QCheckBox(i18n("&Remember choice"), page);
mTopLayout->addWidget(mRememberCB);
mRememberCB->setWhatsThis(
i18n("<qt><p>If you check this box your choice will "
"be stored and you will not be asked again."
"</p></qt>"));
}
connect(mCheckSelectionTimer, &QTimer::timeout,
this, [this] () { slotCheckSelection(); });
connectSignals();
connect(mKeyListView, &Kleo::KeyListView::doubleClicked, this, &KeySelectionDialog::slotTryOk);
connect(mKeyListView, &KeyListView::contextMenu, this, &KeySelectionDialog::slotRMB);
if (options & RereadKeys) {
QPushButton *button = new QPushButton(i18n("&Reread Keys"));
buttonBox->addButton(button, QDialogButtonBox::ActionRole);
connect(button, &QPushButton::clicked, this, &KeySelectionDialog::slotRereadKeys);
}
if (options & ExternalCertificateManager) {
QPushButton *button = new QPushButton(i18n("&Start Certificate Manager"));
buttonBox->addButton(button, QDialogButtonBox::ActionRole);
connect(button, &QPushButton::clicked, this, [this]() { slotStartCertificateManager(); });
}
connect(mOkButton, &QPushButton::clicked, this, &KeySelectionDialog::slotOk);
connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &KeySelectionDialog::slotCancel);
mTopLayout->activate();
if (qApp) {
QSize dialogSize(sizeHint());
KConfigGroup dialogConfig(KSharedConfig::openStateConfig(), "Key Selection Dialog");
dialogSize = dialogConfig.readEntry("Dialog size", dialogSize);
const QByteArray headerState = dialogConfig.readEntry("header", QByteArray());
if (!headerState.isEmpty()) {
mKeyListView->header()->restoreState(headerState);
}
resize(dialogSize);
}
}
void Kleo::KeySelectionDialog::init(bool rememberChoice, bool extendedSelection, const QString &text, const QString &initialQuery)
{
Options options = { RereadKeys, ExternalCertificateManager };
options.setFlag(ExtendedSelection, extendedSelection);
options.setFlag(RememberChoice, rememberChoice);
setUpUI(options, initialQuery);
setText(text);
if (mKeyUsage & OpenPGPKeys) {
mOpenPGPBackend = QGpgME::openpgp();
}
if (mKeyUsage & SMIMEKeys) {
mSMIMEBackend = QGpgME::smime();
}
slotRereadKeys();
}
Kleo::KeySelectionDialog::~KeySelectionDialog()
{
disconnectSignals();
KConfigGroup dialogConfig(KSharedConfig::openStateConfig(), "Key Selection Dialog");
dialogConfig.writeEntry("Dialog size", size());
dialogConfig.writeEntry("header", mKeyListView->header()->saveState());
dialogConfig.sync();
}
void Kleo::KeySelectionDialog::setText(const QString &text)
{
mTextLabel->setText(text);
mTextLabel->setVisible(!text.isEmpty());
}
void Kleo::KeySelectionDialog::setKeys(const std::vector<GpgME::Key> &keys)
{
for (const GpgME::Key &key : keys) {
mKeyListView->slotAddKey(key);
}
}
void Kleo::KeySelectionDialog::connectSignals()
{
if (mKeyListView->isMultiSelection())
connect(mKeyListView, &QTreeWidget::itemSelectionChanged, this, &KeySelectionDialog::slotSelectionChanged);
else
connect(mKeyListView, QOverload<KeyListViewItem*>::of(&KeyListView::selectionChanged),
this, QOverload<KeyListViewItem*>::of(&KeySelectionDialog::slotCheckSelection));
}
void Kleo::KeySelectionDialog::disconnectSignals()
{
if (mKeyListView->isMultiSelection())
disconnect(mKeyListView, &QTreeWidget::itemSelectionChanged,
this, &KeySelectionDialog::slotSelectionChanged);
else
disconnect(mKeyListView, QOverload<KeyListViewItem*>::of(&KeyListView::selectionChanged),
this, QOverload<KeyListViewItem*>::of(&KeySelectionDialog::slotCheckSelection));
}
const GpgME::Key &Kleo::KeySelectionDialog::selectedKey() const
{
static const GpgME::Key null = GpgME::Key::null;
if (mKeyListView->isMultiSelection() || !mKeyListView->selectedItem()) {
return null;
}
return mKeyListView->selectedItem()->key();
}
QString Kleo::KeySelectionDialog::fingerprint() const
{
return QLatin1String(selectedKey().primaryFingerprint());
}
QStringList Kleo::KeySelectionDialog::fingerprints() const
{
QStringList result;
for (auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
QStringList Kleo::KeySelectionDialog::pgpKeyFingerprints() const
{
QStringList result;
for (auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (it->protocol() == GpgME::OpenPGP)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
QStringList Kleo::KeySelectionDialog::smimeFingerprints() const
{
QStringList result;
for (auto it = mSelectedKeys.begin(); it != mSelectedKeys.end(); ++it)
if (it->protocol() == GpgME::CMS)
if (const char *fpr = it->primaryFingerprint()) {
result.push_back(QLatin1String(fpr));
}
return result;
}
void Kleo::KeySelectionDialog::slotRereadKeys()
{
mKeyListView->clear();
mListJobCount = 0;
mTruncated = 0;
mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
disconnectSignals();
mKeyListView->setEnabled(false);
// FIXME: save current selection
if (mOpenPGPBackend) {
startKeyListJobForBackend(mOpenPGPBackend, std::vector<GpgME::Key>(), false /*non-validating*/);
}
if (mSMIMEBackend) {
startKeyListJobForBackend(mSMIMEBackend, std::vector<GpgME::Key>(), false /*non-validating*/);
}
if (mListJobCount == 0) {
mKeyListView->setEnabled(true);
KMessageBox::information(this,
i18n("No backends found for listing keys. "
"Check your installation."),
i18n("Key Listing Failed"));
connectSignals();
}
}
void Kleo::KeySelectionDialog::slotStartCertificateManager(const QString &query)
{
QStringList args;
if (!query.isEmpty()) {
args << QStringLiteral("--search") << query;
}
if (!QProcess::startDetached(QStringLiteral("kleopatra"), args))
KMessageBox::error(this,
i18n("Could not start certificate manager; "
"please check your installation."),
i18n("Certificate Manager Error"));
else {
qCDebug(KLEO_UI_LOG) << "\nslotStartCertManager(): certificate manager started.";
}
}
#ifndef __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
#define __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
static void showKeyListError(QWidget *parent, const GpgME::Error &err)
{
Q_ASSERT(err);
const QString msg = i18n("<qt><p>An error occurred while fetching "
"the keys from the backend:</p>"
"<p><b>%1</b></p></qt>",
QString::fromLocal8Bit(err.asString()));
KMessageBox::error(parent, msg, i18n("Key Listing Failed"));
}
#endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__
namespace
{
struct ExtractFingerprint {
QString operator()(const GpgME::Key &key)
{
return QLatin1String(key.primaryFingerprint());
}
};
}
void Kleo::KeySelectionDialog::startKeyListJobForBackend(const QGpgME::Protocol *backend, const std::vector<GpgME::Key> &keys, bool validate)
{
Q_ASSERT(backend);
- QGpgME::KeyListJob *job = backend->keyListJob(false, false, validate); // local, w/o sigs, validation as givem
+ QGpgME::KeyListJob *job = backend->keyListJob(false, false, validate); // local, w/o sigs, validation as given
if (!job) {
return;
}
connect(job, &QGpgME::KeyListJob::result, this, &KeySelectionDialog::slotKeyListResult);
if (validate)
connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotRefreshKey);
else
connect(job, &QGpgME::KeyListJob::nextKey, mKeyListView, &KeyListView::slotAddKey);
QStringList fprs;
std::transform(keys.begin(), keys.end(), std::back_inserter(fprs), ExtractFingerprint());
const GpgME::Error err = job->start(fprs, mKeyUsage & SecretKeys && !(mKeyUsage & PublicKeys));
if (err) {
return showKeyListError(this, err);
}
#ifndef LIBKLEO_NO_PROGRESSDIALOG
// FIXME: create a MultiProgressDialog:
(void)new ProgressDialog(job, validate ? i18n("Checking selected keys...") : i18n("Fetching keys..."), this);
#endif
++mListJobCount;
}
static void selectKeys(Kleo::KeyListView *klv, const std::vector<GpgME::Key> &selectedKeys)
{
klv->clearSelection();
if (selectedKeys.empty()) {
return;
}
for (auto it = selectedKeys.begin(); it != selectedKeys.end(); ++it)
if (Kleo::KeyListViewItem *item = klv->itemByFingerprint(it->primaryFingerprint())) {
item->setSelected(true);
}
}
void Kleo::KeySelectionDialog::slotKeyListResult(const GpgME::KeyListResult &res)
{
if (res.error()) {
showKeyListError(this, res.error());
} else if (res.isTruncated()) {
++mTruncated;
}
if (--mListJobCount > 0) {
return; // not yet finished...
}
if (mTruncated > 0)
KMessageBox::information(this,
i18np("<qt>One backend returned truncated output.<p>"
"Not all available keys are shown</p></qt>",
"<qt>%1 backends returned truncated output.<p>"
"Not all available keys are shown</p></qt>",
mTruncated),
i18n("Key List Result"));
mKeyListView->flushKeys();
mKeyListView->setEnabled(true);
mListJobCount = mTruncated = 0;
mKeysToCheck.clear();
selectKeys(mKeyListView, mSelectedKeys);
slotFilter();
connectSignals();
slotSelectionChanged();
// restore the saved position of the contents
mKeyListView->verticalScrollBar()->setValue(mSavedOffsetY); mSavedOffsetY = 0;
}
void Kleo::KeySelectionDialog::slotSelectionChanged()
{
qCDebug(KLEO_UI_LOG) << "KeySelectionDialog::slotSelectionChanged()";
// (re)start the check selection timer. Checking the selection is delayed
// because else drag-selection doesn't work very good (checking key trust
// is slow).
mCheckSelectionTimer->start(sCheckSelectionDelay);
}
namespace
{
struct AlreadyChecked {
bool operator()(const GpgME::Key &key) const
{
return key.keyListMode() & GpgME::Validate;
}
};
}
void Kleo::KeySelectionDialog::slotCheckSelection(KeyListViewItem *item)
{
qCDebug(KLEO_UI_LOG) << "KeySelectionDialog::slotCheckSelection()";
mCheckSelectionTimer->stop();
mSelectedKeys.clear();
if (!mKeyListView->isMultiSelection()) {
if (item) {
mSelectedKeys.push_back(item->key());
}
}
for (KeyListViewItem *it = mKeyListView->firstChild(); it; it = it->nextSibling())
if (it->isSelected()) {
mSelectedKeys.push_back(it->key());
}
mKeysToCheck.clear();
std::remove_copy_if(mSelectedKeys.begin(), mSelectedKeys.end(),
std::back_inserter(mKeysToCheck),
AlreadyChecked());
if (mKeysToCheck.empty()) {
mOkButton->setEnabled(!mSelectedKeys.empty() &&
checkKeyUsage(mSelectedKeys, mKeyUsage));
return;
}
// performed all fast checks - now for validating key listing:
startValidatingKeyListing();
}
void Kleo::KeySelectionDialog::startValidatingKeyListing()
{
if (mKeysToCheck.empty()) {
return;
}
mListJobCount = 0;
mTruncated = 0;
mSavedOffsetY = mKeyListView->verticalScrollBar()->value();
disconnectSignals();
mKeyListView->setEnabled(false);
std::vector<GpgME::Key> smime, openpgp;
for (std::vector<GpgME::Key>::const_iterator it = mKeysToCheck.begin(); it != mKeysToCheck.end(); ++it)
if (it->protocol() == GpgME::OpenPGP) {
openpgp.push_back(*it);
} else {
smime.push_back(*it);
}
if (!openpgp.empty()) {
Q_ASSERT(mOpenPGPBackend);
startKeyListJobForBackend(mOpenPGPBackend, openpgp, true /*validate*/);
}
if (!smime.empty()) {
Q_ASSERT(mSMIMEBackend);
startKeyListJobForBackend(mSMIMEBackend, smime, true /*validate*/);
}
Q_ASSERT(mListJobCount > 0);
}
bool Kleo::KeySelectionDialog::rememberSelection() const
{
return mRememberCB && mRememberCB->isChecked();
}
void Kleo::KeySelectionDialog::slotRMB(Kleo::KeyListViewItem *item, const QPoint &p)
{
if (!item) {
return;
}
mCurrentContextMenuItem = item;
QMenu menu;
menu.addAction(i18n("Recheck Key"), this, &KeySelectionDialog::slotRecheckKey);
menu.exec(p);
}
void Kleo::KeySelectionDialog::slotRecheckKey()
{
if (!mCurrentContextMenuItem || mCurrentContextMenuItem->key().isNull()) {
return;
}
mKeysToCheck.clear();
mKeysToCheck.push_back(mCurrentContextMenuItem->key());
}
void Kleo::KeySelectionDialog::slotTryOk()
{
if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
slotOk();
}
}
void Kleo::KeySelectionDialog::slotOk()
{
if (mCheckSelectionTimer->isActive()) {
slotCheckSelection();
}
#if 0 //Laurent I don't understand why we returns here.
// button could be disabled again after checking the selected key1
if (!mSelectedKeys.empty() && checkKeyUsage(mSelectedKeys, mKeyUsage)) {
return;
}
#endif
mStartSearchTimer->stop();
accept();
}
void Kleo::KeySelectionDialog::slotCancel()
{
mCheckSelectionTimer->stop();
mStartSearchTimer->stop();
reject();
}
void Kleo::KeySelectionDialog::slotSearch(const QString &text)
{
mSearchText = text.trimmed().toUpper();
slotSearch();
}
void Kleo::KeySelectionDialog::slotSearch()
{
mStartSearchTimer->setSingleShot(true);
mStartSearchTimer->start(sCheckSelectionDelay);
}
void Kleo::KeySelectionDialog::slotFilter()
{
if (mSearchText.isEmpty()) {
showAllItems();
return;
}
// OK, so we need to filter:
QRegExp keyIdRegExp(QLatin1String("(?:0x)?[A-F0-9]{1,8}"), Qt::CaseInsensitive);
if (keyIdRegExp.exactMatch(mSearchText)) {
if (mSearchText.startsWith(QLatin1String("0X")))
// search for keyID only:
{
filterByKeyID(mSearchText.mid(2));
} else
// search for UID and keyID:
{
filterByKeyIDOrUID(mSearchText);
}
} else {
// search in UID:
filterByUID(mSearchText);
}
}
void Kleo::KeySelectionDialog::filterByKeyID(const QString &keyID)
{
Q_ASSERT(keyID.length() <= 8);
Q_ASSERT(!keyID.isEmpty()); // regexp in slotFilter should prevent these
if (keyID.isEmpty()) {
showAllItems();
} else
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!item->text(0).toUpper().startsWith(keyID));
}
}
static bool anyUIDMatches(const Kleo::KeyListViewItem *item, QRegExp &rx)
{
if (!item) {
return false;
}
const std::vector<GpgME::UserID> uids = item->key().userIDs();
for (auto it = uids.begin(); it != uids.end(); ++it)
if (it->id() && rx.indexIn(QString::fromUtf8(it->id())) >= 0) {
return true;
}
return false;
}
void Kleo::KeySelectionDialog::filterByKeyIDOrUID(const QString &str)
{
Q_ASSERT(!str.isEmpty());
// match beginnings of words:
QRegExp rx(QLatin1String("\\b") + QRegExp::escape(str), Qt::CaseInsensitive);
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!item->text(0).toUpper().startsWith(str) && !anyUIDMatches(item, rx));
}
}
void Kleo::KeySelectionDialog::filterByUID(const QString &str)
{
Q_ASSERT(!str.isEmpty());
// match beginnings of words:
QRegExp rx(QLatin1String("\\b") + QRegExp::escape(str), Qt::CaseInsensitive);
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(!anyUIDMatches(item, rx));
}
}
void Kleo::KeySelectionDialog::showAllItems()
{
for (KeyListViewItem *item = mKeyListView->firstChild(); item; item = item->nextSibling()) {
item->setHidden(false);
}
}
diff --git a/src/utils/formatting.h b/src/utils/formatting.h
index 361cf494..87bfb604 100644
--- a/src/utils/formatting.h
+++ b/src/utils/formatting.h
@@ -1,165 +1,165 @@
/* -*- mode: c++; c-basic-offset:4 -*-
utils/formatting.h
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2021 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <gpgme++/key.h>
#include <kleo_export.h>
class QString;
#include <QStringList>
class QDate;
class QIcon;
namespace GpgME
{
class Import;
}
namespace Kleo
{
class KeyGroup;
namespace Formatting
{
KLEO_EXPORT QString prettyNameAndEMail(int proto, const char *id, const char *name, const char *email, const char *comment);
KLEO_EXPORT QString prettyNameAndEMail(int proto, const QString &id, const QString &name, const QString &email, const QString &comment);
KLEO_EXPORT QString prettyNameAndEMail(const GpgME::Key &key);
KLEO_EXPORT QString prettyNameAndEMail(const GpgME::UserID &key);
KLEO_EXPORT QString prettyUserID(const GpgME::UserID &uid);
KLEO_EXPORT QString prettyKeyID(const char *id);
KLEO_EXPORT QString prettyName(int proto, const char *id, const char *name, const char *comment);
KLEO_EXPORT QString prettyName(const GpgME::Key &key);
KLEO_EXPORT QString prettyName(const GpgME::UserID &uid);
KLEO_EXPORT QString prettyName(const GpgME::UserID::Signature &sig);
KLEO_EXPORT QString prettyEMail(const char *email, const char *id);
KLEO_EXPORT QString prettyEMail(const GpgME::Key &key);
KLEO_EXPORT QString prettyEMail(const GpgME::UserID &uid);
KLEO_EXPORT QString prettyEMail(const GpgME::UserID::Signature &sig);
/* Formats a fingerprint or keyid into groups of four */
KLEO_EXPORT QString prettyID(const char *id);
enum ToolTipOption {
KeyID = 0x001,
Validity = 0x002,
StorageLocation = 0x004,
SerialNumber = 0x008,
Issuer = 0x010,
Subject = 0x020,
ExpiryDates = 0x040,
CertificateType = 0x080,
CertificateUsage = 0x100,
Fingerprint = 0x200,
UserIDs = 0x400,
OwnerTrust = 0x800,
Subkeys = 0x1000,
AllOptions = 0xffff
};
KLEO_EXPORT QString toolTip(const GpgME::Key &key, int opts);
KLEO_EXPORT QString toolTip(const Kleo::KeyGroup &group, int opts);
KLEO_EXPORT QString expirationDateString(const GpgME::Key &key);
KLEO_EXPORT QString expirationDateString(const GpgME::Subkey &subkey);
KLEO_EXPORT QString expirationDateString(const GpgME::UserID::Signature &sig);
KLEO_EXPORT QDate expirationDate(const GpgME::Key &key);
KLEO_EXPORT QDate expirationDate(const GpgME::Subkey &subkey);
KLEO_EXPORT QDate expirationDate(const GpgME::UserID::Signature &sig);
KLEO_EXPORT QString creationDateString(const GpgME::Key &key);
KLEO_EXPORT QString creationDateString(const GpgME::Subkey &subkey);
KLEO_EXPORT QString creationDateString(const GpgME::UserID::Signature &sig);
KLEO_EXPORT QDate creationDate(const GpgME::Key &key);
KLEO_EXPORT QDate creationDate(const GpgME::Subkey &subkey);
KLEO_EXPORT QDate creationDate(const GpgME::UserID::Signature &sig);
/* Convert a GPGME style time to a localized string */
KLEO_EXPORT QString dateString(time_t t);
KLEO_EXPORT QString displayName(GpgME::Protocol prot);
KLEO_EXPORT QString type(const GpgME::Key &key);
KLEO_EXPORT QString type(const GpgME::Subkey &subkey);
KLEO_EXPORT QString type(const Kleo::KeyGroup &group);
KLEO_EXPORT QString ownerTrustShort(const GpgME::Key &key);
KLEO_EXPORT QString ownerTrustShort(GpgME::Key::OwnerTrust trust);
KLEO_EXPORT QString validityShort(const GpgME::Subkey &subkey);
KLEO_EXPORT QString validityShort(const GpgME::UserID &uid);
KLEO_EXPORT QString validityShort(const GpgME::UserID::Signature &sig);
KLEO_EXPORT QIcon validityIcon(const GpgME::UserID::Signature &sig);
/* A sentence about the validity of the UserID */
KLEO_EXPORT QString validity(const GpgME::UserID &uid);
KLEO_EXPORT QString validity(const Kleo::KeyGroup &group);
KLEO_EXPORT QIcon validityIcon(const Kleo::KeyGroup &group);
KLEO_EXPORT QString formatForComboBox(const GpgME::Key &key);
KLEO_EXPORT QString formatKeyLink(const GpgME::Key &key);
KLEO_EXPORT QString signatureToString(const GpgME::Signature &sig, const GpgME::Key &key);
KLEO_EXPORT const char *summaryToString(const GpgME::Signature::Summary summary);
KLEO_EXPORT QString importMetaData(const GpgME::Import &import);
KLEO_EXPORT QString importMetaData(const GpgME::Import &import, const QStringList &sources);
KLEO_EXPORT QString formatOverview(const GpgME::Key &key);
KLEO_EXPORT QString usageString(const GpgME::Subkey &subkey);
KLEO_EXPORT QString summaryLine(const GpgME::Key &key);
KLEO_EXPORT QString summaryLine(const KeyGroup &group);
KLEO_EXPORT QIcon iconForUid(const GpgME::UserID &uid);
/* Is the key valid i.e. are all uids fully trusted? */
KLEO_EXPORT bool uidsHaveFullValidity(const GpgME::Key &key);
/* The compliance mode of the gnupg system. Empty if compliance
* mode is not set. */
KLEO_EXPORT QString complianceMode();
/* Is the given key in compliance with CO_DE_VS? */
KLEO_EXPORT bool isKeyDeVs(const GpgME::Key &key);
/* Localized string describing the name of the VS-NfD Compliance filter. If
* compliant is false the name of the not Compliant filter.
*
* This is required to make the string configurable which is
* a common request from users because VS-NfD compliance is called
- * differently in different enviornments. E.g NATO RESTRICTED or
+ * differently in different environments. E.g NATO RESTRICTED or
* EU RESTRICTED. */
KLEO_EXPORT QString deVsString (bool compliant = true);
/* A sentence if the key confirms to the current compliance mode */
KLEO_EXPORT QString complianceStringForKey(const GpgME::Key &key);
/* A single word for use in keylists to describe the validity of the
* given key, including any conformance statements relevant to the
* current conformance mode. */
KLEO_EXPORT QString complianceStringShort(const GpgME::Key &key);
KLEO_EXPORT QString complianceStringShort(const Kleo::KeyGroup &group);
/* The origin of the key mapped to a localized string */
KLEO_EXPORT QString origin(int o);
/* Human-readable trust signature scope (for trust signature regexp created by GnuPG) */
KLEO_EXPORT QString trustSignatureDomain(const GpgME::UserID::Signature &sig);
/* Summary of trust signature properties */
KLEO_EXPORT QString trustSignature(const GpgME::UserID::Signature &sig);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Feb 26, 7:20 PM (12 h, 34 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
53/ca/481d4c6dc0ffedf3171967d9133f

Event Timeline