File indexing completed on 2024-11-24 04:49:36

0001 /*
0002     kconfigbasedkeyfilter.cpp
0003 
0004     This file is part of libkleopatra, the KDE keymanagement library
0005     SPDX-FileCopyrightText: 2004 Klarälvdalens Datakonsult AB
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include <config-libkleo.h>
0011 
0012 #include "kconfigbasedkeyfilter.h"
0013 
0014 #include <KConfigBase>
0015 #include <KConfigGroup>
0016 
0017 #include <QDebug>
0018 #include <QRegularExpression>
0019 
0020 #include <algorithm>
0021 
0022 using namespace Kleo;
0023 using namespace GpgME;
0024 
0025 //
0026 //
0027 // FontDescription - intuitive font property resolving
0028 //                   (QFont::resolve doesn't work for us)
0029 //
0030 //
0031 struct KeyFilter::FontDescription::Private {
0032     bool bold, italic, strikeOut, fullFont;
0033     QFont font;
0034 };
0035 
0036 KeyFilter::FontDescription::FontDescription()
0037     : d(new Private)
0038 {
0039     d->bold = d->italic = d->strikeOut = d->fullFont = false;
0040 }
0041 
0042 KeyFilter::FontDescription::FontDescription(const FontDescription &other)
0043     : d(new Private(*other.d))
0044 {
0045 }
0046 
0047 KeyFilter::FontDescription::~FontDescription() = default;
0048 
0049 KeyFilter::FontDescription KeyFilter::FontDescription::create(bool b, bool i, bool s)
0050 {
0051     FontDescription fd;
0052     fd.d->bold = b;
0053     fd.d->italic = i;
0054     fd.d->strikeOut = s;
0055     return fd;
0056 }
0057 
0058 KeyFilter::FontDescription KeyFilter::FontDescription::create(const QFont &f, bool b, bool i, bool s)
0059 {
0060     FontDescription fd;
0061     fd.d->fullFont = true;
0062     fd.d->font = f;
0063     fd.d->bold = b;
0064     fd.d->italic = i;
0065     fd.d->strikeOut = s;
0066     return fd;
0067 }
0068 
0069 QFont KeyFilter::FontDescription::font(const QFont &base) const
0070 {
0071     QFont font;
0072     if (d->fullFont) {
0073         font = d->font;
0074         font.setPointSize(base.pointSize());
0075     } else {
0076         font = base;
0077     }
0078     if (d->bold) {
0079         font.setBold(true);
0080     }
0081     if (d->italic) {
0082         font.setItalic(true);
0083     }
0084     if (d->strikeOut) {
0085         font.setStrikeOut(true);
0086     }
0087     return font;
0088 }
0089 
0090 KeyFilter::FontDescription KeyFilter::FontDescription::resolve(const FontDescription &other) const
0091 {
0092     FontDescription fd;
0093     fd.d->fullFont = this->d->fullFont || other.d->fullFont;
0094     if (fd.d->fullFont) {
0095         fd.d->font = this->d->fullFont ? this->d->font : other.d->font;
0096     }
0097     fd.d->bold = this->d->bold || other.d->bold;
0098     fd.d->italic = this->d->italic || other.d->italic;
0099     fd.d->strikeOut = this->d->strikeOut || other.d->strikeOut;
0100     return fd;
0101 }
0102 
0103 static const struct {
0104     const char *name;
0105     Key::OwnerTrust trust;
0106     UserID::Validity validity;
0107 } ownerTrustAndValidityMap[] = {
0108     // clang-format off
0109     {"unknown",   Key::Unknown,   UserID::Unknown  },
0110     {"undefined", Key::Undefined, UserID::Undefined},
0111     {"never",     Key::Never,     UserID::Never    },
0112     {"marginal",  Key::Marginal,  UserID::Marginal },
0113     {"full",      Key::Full,      UserID::Full     },
0114     {"ultimate",  Key::Ultimate,  UserID::Ultimate },
0115     // clang-format on
0116 };
0117 
0118 static Key::OwnerTrust map2OwnerTrust(const QString &s)
0119 {
0120     for (unsigned int i = 0; i < sizeof ownerTrustAndValidityMap / sizeof *ownerTrustAndValidityMap; ++i) {
0121         if (s.toLower() == QLatin1StringView(ownerTrustAndValidityMap[i].name)) {
0122             return ownerTrustAndValidityMap[i].trust;
0123         }
0124     }
0125     return ownerTrustAndValidityMap[0].trust;
0126 }
0127 
0128 static UserID::Validity map2Validity(const QString &s)
0129 {
0130     for (unsigned int i = 0; i < sizeof ownerTrustAndValidityMap / sizeof *ownerTrustAndValidityMap; ++i) {
0131         if (s.toLower() == QLatin1StringView(ownerTrustAndValidityMap[i].name)) {
0132             return ownerTrustAndValidityMap[i].validity;
0133         }
0134     }
0135     return ownerTrustAndValidityMap[0].validity;
0136 }
0137 
0138 KConfigBasedKeyFilter::KConfigBasedKeyFilter(const KConfigGroup &config)
0139     : DefaultKeyFilter()
0140 {
0141     setFgColor(config.readEntry<QColor>("foreground-color", QColor()));
0142     setBgColor(config.readEntry<QColor>("background-color", QColor()));
0143     setName(config.readEntry("Name", config.name()));
0144     setIcon(config.readEntry("icon"));
0145     setId(config.readEntry("id", config.name()));
0146     if (config.hasKey("font")) {
0147         setUseFullFont(true);
0148         setFont(config.readEntry("font"));
0149     } else {
0150         setUseFullFont(false);
0151         setItalic(config.readEntry("font-italic", false));
0152         setBold(config.readEntry("font-bold", false));
0153     }
0154     setStrikeOut(config.readEntry("font-strikeout", false));
0155 #ifdef SET
0156 #undef SET
0157 #endif
0158 #define SET(member, key)                                                                                                                                       \
0159     if (config.hasKey(key)) {                                                                                                                                  \
0160         set##member(config.readEntry(key, false) ? Set : NotSet);                                                                                              \
0161         setSpecificity(specificity() + 1);                                                                                                                     \
0162     }
0163     SET(Revoked, "is-revoked");
0164     SET(Expired, "is-expired");
0165     SET(Disabled, "is-disabled");
0166     SET(Root, "is-root-certificate");
0167     SET(CanEncrypt, "can-encrypt");
0168     SET(CanSign, "can-sign");
0169     SET(CanCertify, "can-certify");
0170     SET(CanAuthenticate, "can-authenticate");
0171     SET(HasEncrypt, "has-encrypt");
0172     SET(HasSign, "has-sign");
0173     SET(HasCertify, "has-certify");
0174     SET(HasAuthenticate, "has-authenticate");
0175     SET(Qualified, "is-qualified");
0176     SET(CardKey, "is-cardkey");
0177     SET(HasSecret, "has-secret-key");
0178     SET(IsOpenPGP, "is-openpgp-key");
0179     SET(WasValidated, "was-validated");
0180     SET(IsDeVs, "is-de-vs");
0181 #undef SET
0182     static const struct {
0183         const char *prefix;
0184         LevelState state;
0185     } prefixMap[] = {
0186         {"is-", Is},
0187         {"is-not-", IsNot},
0188         {"is-at-least-", IsAtLeast},
0189         {"is-at-most-", IsAtMost},
0190     };
0191     for (unsigned int i = 0; i < sizeof prefixMap / sizeof *prefixMap; ++i) {
0192         const QString key = QLatin1StringView(prefixMap[i].prefix) + QLatin1String("ownertrust");
0193         if (config.hasKey(key)) {
0194             setOwnerTrust(prefixMap[i].state);
0195             setOwnerTrustReferenceLevel(map2OwnerTrust(config.readEntry(key, QString())));
0196             setSpecificity(specificity() + 1);
0197             break;
0198         }
0199     }
0200     for (unsigned int i = 0; i < sizeof prefixMap / sizeof *prefixMap; ++i) {
0201         const QString key = QLatin1StringView(prefixMap[i].prefix) + QLatin1String("validity");
0202         if (config.hasKey(key)) {
0203             setValidity(prefixMap[i].state);
0204             setValidityReferenceLevel(map2Validity(config.readEntry(key, QString())));
0205             setSpecificity(specificity() + 1);
0206             break;
0207         }
0208     }
0209     static const struct {
0210         const char *key;
0211         MatchContext context;
0212     } matchMap[] = {
0213         {"any", AnyMatchContext},
0214         {"appearance", Appearance},
0215         {"filtering", Filtering},
0216     };
0217     static const QRegularExpression reg(QRegularExpression(QLatin1StringView("[^a-z!]+")));
0218     const QStringList contexts = config.readEntry("match-contexts", "any").toLower().split(reg, Qt::SkipEmptyParts);
0219     setMatchContexts(NoMatchContext);
0220     for (const QString &ctx : contexts) {
0221         bool found = false;
0222         for (unsigned int i = 0; i < sizeof matchMap / sizeof *matchMap; ++i) {
0223             if (ctx == QLatin1StringView(matchMap[i].key)) {
0224                 setMatchContexts(availableMatchContexts() |= matchMap[i].context);
0225                 found = true;
0226                 break;
0227             } else if (ctx.startsWith(QLatin1Char('!')) && ctx.mid(1) == QLatin1StringView(matchMap[i].key)) {
0228                 setMatchContexts(availableMatchContexts() &= matchMap[i].context);
0229                 found = true;
0230                 break;
0231             }
0232         }
0233         if (!found) {
0234             qWarning() << QStringLiteral("KConfigBasedKeyFilter: found unknown match context '%1' in group '%2'").arg(ctx, config.name());
0235         }
0236     }
0237     if (availableMatchContexts() == NoMatchContext) {
0238         qWarning() << QStringLiteral(
0239                           "KConfigBasedKeyFilter: match context in group '%1' evaluates to NoMatchContext, "
0240                           "replaced by AnyMatchContext")
0241                           .arg(config.name());
0242         setMatchContexts(AnyMatchContext);
0243     }
0244 }