diff --git a/src/kleo/kconfigbasedkeyfilter.cpp b/src/kleo/kconfigbasedkeyfilter.cpp index 72d65840d..b21a45f23 100644 --- a/src/kleo/kconfigbasedkeyfilter.cpp +++ b/src/kleo/kconfigbasedkeyfilter.cpp @@ -1,235 +1,232 @@ /* kconfigbasedkeyfilter.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 "kconfigbasedkeyfilter.h" #include #include #include #include using namespace Kleo; using namespace GpgME; // // // FontDescription - intuitive font property resolving // (QFont::resolve doesn't work for us) // // struct KeyFilter::FontDescription::Private { bool bold, italic, strikeOut, fullFont; QFont font; }; KeyFilter::FontDescription::FontDescription() : d(new Private) { d->bold = d->italic = d->strikeOut = d->fullFont = false; } KeyFilter::FontDescription::FontDescription(const FontDescription &other) : d(new Private(*other.d)) { } -KeyFilter::FontDescription::~FontDescription() -{ - delete d; -} +KeyFilter::FontDescription::~FontDescription() = default; KeyFilter::FontDescription KeyFilter::FontDescription::create(bool b, bool i, bool s) { FontDescription fd; fd.d->bold = b; fd.d->italic = i; fd.d->strikeOut = s; return fd; } KeyFilter::FontDescription KeyFilter::FontDescription::create(const QFont &f, bool b, bool i, bool s) { FontDescription fd; fd.d->fullFont = true; fd.d->font = f; fd.d->bold = b; fd.d->italic = i; fd.d->strikeOut = s; return fd; } QFont KeyFilter::FontDescription::font(const QFont &base) const { QFont font; if (d->fullFont) { font = d->font; font.setPointSize(base.pointSize()); } else { font = base; } if (d->bold) { font.setBold(true); } if (d->italic) { font.setItalic(true); } if (d->strikeOut) { font.setStrikeOut(true); } return font; } KeyFilter::FontDescription KeyFilter::FontDescription::resolve(const FontDescription &other) const { FontDescription fd; fd.d->fullFont = this->d->fullFont || other.d->fullFont; if (fd.d->fullFont) { fd.d->font = this->d->fullFont ? this->d->font : other.d->font; } fd.d->bold = this->d->bold || other.d->bold; fd.d->italic = this->d->italic || other.d->italic; fd.d->strikeOut = this->d->strikeOut || other.d->strikeOut; return fd; } static const struct { const char *name; Key::OwnerTrust trust; UserID::Validity validity; } ownerTrustAndValidityMap[] = { { "unknown", Key::Unknown, UserID::Unknown }, { "undefined", Key::Undefined, UserID::Undefined }, { "never", Key::Never, UserID::Never }, { "marginal", Key::Marginal, UserID::Marginal }, { "full", Key::Full, UserID::Full }, { "ultimate", Key::Ultimate, UserID::Ultimate }, }; static Key::OwnerTrust map2OwnerTrust(const QString &s) { for (unsigned int i = 0; i < sizeof ownerTrustAndValidityMap / sizeof *ownerTrustAndValidityMap; ++i) { if (s.toLower() == QLatin1String(ownerTrustAndValidityMap[i].name)) { return ownerTrustAndValidityMap[i].trust; } } return ownerTrustAndValidityMap[0].trust; } static UserID::Validity map2Validity(const QString &s) { for (unsigned int i = 0; i < sizeof ownerTrustAndValidityMap / sizeof *ownerTrustAndValidityMap; ++i) { if (s.toLower() == QLatin1String(ownerTrustAndValidityMap[i].name)) { return ownerTrustAndValidityMap[i].validity; } } return ownerTrustAndValidityMap[0].validity; } KConfigBasedKeyFilter::KConfigBasedKeyFilter(const KConfigGroup &config) : DefaultKeyFilter() { setFgColor(config.readEntry("foreground-color", QColor())); setBgColor(config.readEntry("background-color", QColor())); setName(config.readEntry("Name", config.name())); setIcon(config.readEntry("icon")); setId(config.readEntry("id", config.name())); if (config.hasKey("font")) { setUseFullFont(true); setFont(config.readEntry("font")); } else { setUseFullFont(false); setItalic(config.readEntry("font-italic", false)); setBold(config.readEntry("font-bold", false)); } setStrikeOut(config.readEntry("font-strikeout", false)); #ifdef SET #undef SET #endif #define SET(member,key) \ if ( config.hasKey( key ) ) { \ set##member(config.readEntry( key, false ) ? Set : NotSet); \ setSpecificity(specificity() + 1); \ } SET(Revoked, "is-revoked"); SET(Expired, "is-expired"); SET(Disabled, "is-disabled"); SET(Root, "is-root-certificate"); SET(CanEncrypt, "can-encrypt"); SET(CanSign, "can-sign"); SET(CanCertify, "can-certify"); SET(CanAuthenticate, "can-authenticate"); SET(Qualified, "is-qualified"); SET(CardKey, "is-cardkey"); SET(HasSecret, "has-secret-key"); SET(IsOpenPGP, "is-openpgp-key"); SET(WasValidated, "was-validated"); SET(IsDeVs, "is-de-vs"); #undef SET static const struct { const char *prefix; LevelState state; } prefixMap[] = { { "is-", Is }, { "is-not-", IsNot }, { "is-at-least-", IsAtLeast }, { "is-at-most-", IsAtMost }, }; for (unsigned int i = 0; i < sizeof prefixMap / sizeof * prefixMap; ++i) { const QString key = QLatin1String(prefixMap[i].prefix) + QLatin1String("ownertrust"); if (config.hasKey(key)) { setOwnerTrust(prefixMap[i].state); setOwnerTrustReferenceLevel(map2OwnerTrust(config.readEntry(key, QString()))); setSpecificity(specificity() + 1); break; } } for (unsigned int i = 0; i < sizeof prefixMap / sizeof * prefixMap; ++i) { const QString key = QLatin1String(prefixMap[i].prefix) + QLatin1String("validity"); if (config.hasKey(key)) { setValidity(prefixMap[i].state); setValidityReferenceLevel(map2Validity(config.readEntry(key, QString()))); setSpecificity(specificity() + 1); break; } } static const struct { const char *key; MatchContext context; } matchMap[] = { { "any", AnyMatchContext }, { "appearance", Appearance }, { "filtering", Filtering }, }; const QStringList contexts = config.readEntry("match-contexts", "any").toLower().split(QRegExp(QLatin1String("[^a-zA-Z0-9_-!]+")), Qt::SkipEmptyParts); setMatchContexts(NoMatchContext); for (const QString & ctx : contexts) { bool found = false; for (unsigned int i = 0; i < sizeof matchMap / sizeof *matchMap; ++i) { if (ctx == QLatin1String(matchMap[i].key)) { setMatchContexts(availableMatchContexts() |= matchMap[i].context); found = true; break; } else if (ctx.startsWith(QLatin1Char('!')) && ctx.mid(1) == QLatin1String(matchMap[i].key)) { setMatchContexts(availableMatchContexts() &= matchMap[i].context); found = true; break; } } if (!found) { qWarning() << QStringLiteral("KConfigBasedKeyFilter: found unknown match context '%1' in group '%2'").arg(ctx, config.name()); } } if (availableMatchContexts() == NoMatchContext) { qWarning() << QStringLiteral("KConfigBasedKeyFilter: match context in group '%1' evaluates to NoMatchContext, " "replaced by AnyMatchContext").arg(config.name()); setMatchContexts(AnyMatchContext); } } diff --git a/src/kleo/keyfilter.h b/src/kleo/keyfilter.h index 9a6dc9e56..1616e7b82 100644 --- a/src/kleo/keyfilter.h +++ b/src/kleo/keyfilter.h @@ -1,99 +1,99 @@ /* keyfilter.h 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 */ #pragma once #include #include #include - +#include namespace GpgME { class Key; } class QFont; class QColor; class QString; namespace Kleo { /** @short An abstract base class key filters */ class KLEO_EXPORT KeyFilter { public: virtual ~KeyFilter() {} enum MatchContext { NoMatchContext = 0x0, Appearance = 0x1, Filtering = 0x2, AnyMatchContext = Appearance | Filtering }; Q_DECLARE_FLAGS(MatchContexts, MatchContext) virtual bool matches(const GpgME::Key &key, MatchContexts ctx) const = 0; virtual unsigned int specificity() const = 0; virtual QString id() const = 0; virtual MatchContexts availableMatchContexts() const = 0; // not sure if we want these here, but for the time being, it's // the easiest way: virtual QColor fgColor() const = 0; virtual QColor bgColor() const = 0; virtual QString name() const = 0; virtual QString icon() const = 0; class FontDescription { public: FontDescription(); FontDescription(const FontDescription &other); FontDescription &operator=(const FontDescription &other) { FontDescription copy(other); swap(copy); return *this; } ~FontDescription(); static FontDescription create(bool bold, bool italic, bool strikeOut); static FontDescription create(const QFont &font, bool bold, bool italic, bool strikeOut); QFont font(const QFont &base) const; FontDescription resolve(const FontDescription &other) const; void swap(FontDescription &other) { std::swap(this->d, other.d); } struct Private; private: - Private *d; + std::unique_ptr d; }; virtual FontDescription fontDescription() const = 0; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KeyFilter::MatchContexts) } #include Q_DECLARE_METATYPE(Kleo::KeyFilter::MatchContexts) diff --git a/src/kleo/keyfiltermanager.cpp b/src/kleo/keyfiltermanager.cpp index 810350766..7c29a6c92 100644 --- a/src/kleo/keyfiltermanager.cpp +++ b/src/kleo/keyfiltermanager.cpp @@ -1,407 +1,406 @@ /* keyfiltermanager.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 "keyfiltermanager.h" #include "kconfigbasedkeyfilter.h" #include "defaultkeyfilter.h" #include "stl_util.h" #include "libkleo_debug.h" #include "utils/formatting.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace GpgME; namespace { class Model : public QAbstractListModel { KeyFilterManager::Private *m_keyFilterManagerPrivate; public: explicit Model(KeyFilterManager::Private *p) : QAbstractListModel(nullptr), m_keyFilterManagerPrivate(p) {} int rowCount(const QModelIndex &) const override; QVariant data(const QModelIndex &idx, int role) const override; /* upgrade to public */ using QAbstractListModel::beginResetModel; /* upgrade to public */ using QAbstractListModel::endResetModel; }; class AllCertificatesKeyFilter : public DefaultKeyFilter { public: AllCertificatesKeyFilter() : DefaultKeyFilter() { setSpecificity(UINT_MAX); // overly high for ordering setName(i18n("All Certificates")); setId(QStringLiteral("all-certificates")); setMatchContexts(Filtering); } }; class MyCertificatesKeyFilter : public DefaultKeyFilter { public: MyCertificatesKeyFilter() : DefaultKeyFilter() { setHasSecret(Set); setSpecificity(UINT_MAX - 1); // overly high for ordering setName(i18n("My Certificates")); setId(QStringLiteral("my-certificates")); setMatchContexts(AnyMatchContext); setBold(true); } }; class TrustedCertificatesKeyFilter : public DefaultKeyFilter { public: TrustedCertificatesKeyFilter() : DefaultKeyFilter() { setRevoked(NotSet); setValidity(IsAtLeast); setValidityReferenceLevel(UserID::Marginal); setSpecificity(UINT_MAX - 2); // overly high for ordering setName(i18n("Trusted Certificates")); setId(QStringLiteral("trusted-certificates")); setMatchContexts(Filtering); } }; class FullCertificatesKeyFilter : public DefaultKeyFilter { public: FullCertificatesKeyFilter() : DefaultKeyFilter() { setRevoked(NotSet); setValidity(IsAtLeast); setValidityReferenceLevel(UserID::Full); setSpecificity(UINT_MAX - 3); setName(i18n("Fully Trusted Certificates")); setId(QStringLiteral("full-certificates")); setMatchContexts(Filtering); } }; class OtherCertificatesKeyFilter : public DefaultKeyFilter { public: OtherCertificatesKeyFilter() : DefaultKeyFilter() { setHasSecret(NotSet); setValidity(IsAtMost); setValidityReferenceLevel(UserID::Never); setSpecificity(UINT_MAX - 4); // overly high for ordering setName(i18n("Other Certificates")); setId(QStringLiteral("other-certificates")); setMatchContexts(Filtering); } }; /* This filter selects only invalid keys (i.e. those where not all * UIDs are at least fully valid). */ class KeyNotValidFilter : public DefaultKeyFilter { public: KeyNotValidFilter() : DefaultKeyFilter() { setName(i18n("Not validated Certificates")); setId(QStringLiteral("not-validated-certificates")); setSpecificity(UINT_MAX - 6); // overly high for ordering } bool matches (const Key &key, MatchContexts contexts) const override { return (contexts & Filtering) && !Formatting::uidsHaveFullValidity(key); } }; } static std::vector> defaultFilters() { std::vector > result; result.reserve(6); result.push_back(std::shared_ptr(new MyCertificatesKeyFilter)); result.push_back(std::shared_ptr(new TrustedCertificatesKeyFilter)); result.push_back(std::shared_ptr(new FullCertificatesKeyFilter)); result.push_back(std::shared_ptr(new OtherCertificatesKeyFilter)); result.push_back(std::shared_ptr(new AllCertificatesKeyFilter)); result.push_back(std::shared_ptr(new KeyNotValidFilter)); return result; } class KeyFilterManager::Private { public: Private() : filters(), model(this) {} void clear() { model.beginResetModel(); filters.clear(); model.endResetModel(); } std::vector> filters; Model model; }; KeyFilterManager *KeyFilterManager::mSelf = nullptr; KeyFilterManager::KeyFilterManager(QObject *parent) : QObject(parent), d(new Private) { mSelf = this; // ### DF: doesn't a KStaticDeleter work more reliably? if (QCoreApplication *app = QCoreApplication::instance()) { connect(app, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); } reload(); } KeyFilterManager::~KeyFilterManager() { mSelf = nullptr; if (d) { d->clear(); } - delete d; d = nullptr; } KeyFilterManager *KeyFilterManager::instance() { if (!mSelf) { mSelf = new KeyFilterManager(); } return mSelf; } const std::shared_ptr &KeyFilterManager::filterMatching(const Key &key, KeyFilter::MatchContexts contexts) const { const auto it = std::find_if(d->filters.cbegin(), d->filters.cend(), [&key, contexts](const std::shared_ptr &filter) { return filter->matches(key, contexts); }); if (it != d->filters.cend()) { return *it; } static const std::shared_ptr null; return null; } std::vector> KeyFilterManager::filtersMatching(const Key &key, KeyFilter::MatchContexts contexts) const { std::vector> result; result.reserve(d->filters.size()); std::remove_copy_if(d->filters.begin(), d->filters.end(), std::back_inserter(result), [&key, contexts](const std::shared_ptr &filter) { return !filter->matches(key, contexts); }); return result; } namespace { struct ByDecreasingSpecificity : std::binary_function, std::shared_ptr, bool> { bool operator()(const std::shared_ptr &lhs, const std::shared_ptr &rhs) const { return lhs->specificity() > rhs->specificity(); } }; } void KeyFilterManager::reload() { d->clear(); d->filters = defaultFilters(); KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc")); const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Key Filter #\\d+$"))); bool ignoreDeVs = Formatting::complianceMode() != QLatin1String("de-vs"); for (QStringList::const_iterator it = groups.begin(); it != groups.end(); ++it) { const KConfigGroup cfg(config, *it); if (cfg.hasKey("is-de-vs") && ignoreDeVs) { /* Don't show de-vs filters in other compliance modes */ continue; } d->filters.push_back(std::shared_ptr(new KConfigBasedKeyFilter(cfg))); } std::stable_sort(d->filters.begin(), d->filters.end(), ByDecreasingSpecificity()); qCDebug(LIBKLEO_LOG) << "final filter count is" << d->filters.size(); } QAbstractItemModel *KeyFilterManager::model() const { return &d->model; } const std::shared_ptr &KeyFilterManager::keyFilterByID(const QString &id) const { const auto it = std::find_if(d->filters.begin(), d->filters.end(), [id](const std::shared_ptr &filter) { return filter->id() == id; }); if (it != d->filters.end()) { return *it; } static const std::shared_ptr null; return null; } const std::shared_ptr &KeyFilterManager::fromModelIndex(const QModelIndex &idx) const { if (!idx.isValid() || idx.model() != &d->model || idx.row() < 0 || static_cast(idx.row()) >= d->filters.size()) { static const std::shared_ptr null; return null; } return d->filters[idx.row()]; } QModelIndex KeyFilterManager::toModelIndex(const std::shared_ptr &kf) const { if (!kf) { return {}; } const auto pair = std::equal_range(d->filters.cbegin(), d->filters.cend(), kf, ByDecreasingSpecificity()); const auto it = std::find(pair.first, pair.second, kf); if (it != pair.second) { return d->model.index(it - d->filters.begin()); } else { return QModelIndex(); } } int Model::rowCount(const QModelIndex &) const { return m_keyFilterManagerPrivate->filters.size(); } QVariant Model::data(const QModelIndex &idx, int role) const { if (!idx.isValid() || idx.model() != this || idx.row() < 0 || static_cast(idx.row()) > m_keyFilterManagerPrivate->filters.size()) { return QVariant(); } const auto filter = m_keyFilterManagerPrivate->filters[idx.row()]; switch (role) { case Qt::DecorationRole: return filter->icon(); case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: /* Most useless tooltip ever. */ return filter->name(); case KeyFilterManager::FilterIdRole: return filter->id(); case KeyFilterManager::FilterMatchContextsRole: return QVariant::fromValue(filter->availableMatchContexts()); default: return QVariant(); } } static KeyFilter::FontDescription get_fontdescription(const std::vector> &filters, const Key &key, const KeyFilter::FontDescription &initial) { return kdtools::accumulate_if(filters.begin(), filters.end(), [&key](const std::shared_ptr &filter) { return filter->matches(key, KeyFilter::Appearance); }, initial, [](const KeyFilter::FontDescription &lhs, const std::shared_ptr &rhs) { return lhs.resolve(rhs->fontDescription()); }); } QFont KeyFilterManager::font(const Key &key, const QFont &baseFont) const { const KeyFilter::FontDescription fd = get_fontdescription(d->filters, key, KeyFilter::FontDescription()); return fd.font(baseFont); } static QColor get_color(const std::vector> &filters, const Key &key, QColor(KeyFilter::*fun)() const) { const auto it = std::find_if(filters.cbegin(), filters.cend(), [&fun, &key](const std::shared_ptr &filter) { return filter->matches(key, KeyFilter::Appearance) && (filter.get()->*fun)().isValid(); }); if (it == filters.cend()) { return {}; } else { return (it->get()->*fun)(); } } static QString get_string(const std::vector> &filters, const Key &key, QString(KeyFilter::*fun)() const) { const auto it = std::find_if(filters.cbegin(), filters.cend(), [&fun, &key](const std::shared_ptr &filter) { return filter->matches(key, KeyFilter::Appearance) && !(filter.get()->*fun)().isEmpty(); }); if (it == filters.cend()) { return QString(); } else { return (*it)->icon(); } } QColor KeyFilterManager::bgColor(const Key &key) const { return get_color(d->filters, key, &KeyFilter::bgColor); } QColor KeyFilterManager::fgColor(const Key &key) const { return get_color(d->filters, key, &KeyFilter::fgColor); } QIcon KeyFilterManager::icon(const Key &key) const { const QString icon = get_string(d->filters, key, &KeyFilter::icon); return icon.isEmpty() ? QIcon() : QIcon::fromTheme(icon); } diff --git a/src/kleo/keyfiltermanager.h b/src/kleo/keyfiltermanager.h index 0c5ad1c44..4eca65247 100644 --- a/src/kleo/keyfiltermanager.h +++ b/src/kleo/keyfiltermanager.h @@ -1,73 +1,73 @@ /* keyfiltermanager.h 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 */ #pragma once #include "kleo_export.h" #include #include #include #include namespace GpgME { class Key; } class QAbstractItemModel; class QModelIndex; class QFont; class QColor; class QIcon; namespace Kleo { class KLEO_EXPORT KeyFilterManager : public QObject { Q_OBJECT public: enum ModelRoles { FilterIdRole = Qt::UserRole, FilterMatchContextsRole, }; protected: explicit KeyFilterManager(QObject *parent = nullptr); ~KeyFilterManager(); public: static KeyFilterManager *instance(); const std::shared_ptr &filterMatching(const GpgME::Key &key, KeyFilter::MatchContexts contexts) const; std::vector> filtersMatching(const GpgME::Key &key, KeyFilter::MatchContexts contexts) const; QAbstractItemModel *model() const; const std::shared_ptr &keyFilterByID(const QString &id) const; const std::shared_ptr &fromModelIndex(const QModelIndex &mi) const; QModelIndex toModelIndex(const std::shared_ptr &kf) const; void reload(); QFont font(const GpgME::Key &key, const QFont &baseFont) const; QColor bgColor(const GpgME::Key &key) const; QColor fgColor(const GpgME::Key &key) const; QIcon icon(const GpgME::Key &key) const; class Private; private: - Private *d; + std::unique_ptr d; static KeyFilterManager *mSelf; }; }