diff --git a/src/ui/keyrequester.cpp b/src/ui/keyrequester.cpp index eb35c6caa..bb55264a5 100644 --- a/src/ui/keyrequester.cpp +++ b/src/ui/keyrequester.cpp @@ -1,513 +1,513 @@ /* -*- c++ -*- keyrequester.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 This file is part of KPGP, the KDE PGP/GnuPG support library. SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "keyrequester.h" #include "keyselectiondialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace QGpgME; using namespace Kleo; Kleo::KeyRequester::KeyRequester(unsigned int allowedKeys, bool multipleKeys, QWidget *parent) : QWidget(parent) , mOpenPGPBackend(nullptr) , mSMIMEBackend(nullptr) , mMulti(multipleKeys) , mKeyUsage(allowedKeys) , mJobs(0) , d(nullptr) { init(); } Kleo::KeyRequester::KeyRequester(QWidget *parent) : QWidget(parent) , mOpenPGPBackend(nullptr) , mSMIMEBackend(nullptr) , mMulti(false) , mKeyUsage(0) , mJobs(0) , d(nullptr) { init(); } void Kleo::KeyRequester::init() { auto hlay = new QHBoxLayout(this); hlay->setContentsMargins(0, 0, 0, 0); if (DeVSCompliance::isCompliant()) { mComplianceIcon = new QLabel{this}; mComplianceIcon->setPixmap(QIcon::fromTheme(QStringLiteral("emblem-question")).pixmap(22)); } // the label where the key id is to be displayed: mLabel = new QLabel(this); mLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); // the button to unset any key: mEraseButton = new QPushButton(this); mEraseButton->setAutoDefault(false); mEraseButton->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); mEraseButton->setIcon( QIcon::fromTheme(QApplication::isRightToLeft() ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl"))); mEraseButton->setToolTip(i18n("Clear")); // the button to call the KeySelectionDialog: mDialogButton = new QPushButton(i18n("Change..."), this); mDialogButton->setAutoDefault(false); if (mComplianceIcon) { hlay->addWidget(mComplianceIcon); } hlay->addWidget(mLabel, 1); hlay->addWidget(mEraseButton); hlay->addWidget(mDialogButton); connect(mEraseButton, &QPushButton::clicked, this, &SigningKeyRequester::slotEraseButtonClicked); connect(mDialogButton, &QPushButton::clicked, this, &SigningKeyRequester::slotDialogButtonClicked); setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed)); setAllowedKeys(mKeyUsage); } Kleo::KeyRequester::~KeyRequester() { } const std::vector &Kleo::KeyRequester::keys() const { return mKeys; } const GpgME::Key &Kleo::KeyRequester::key() const { static const GpgME::Key null = GpgME::Key::null; if (mKeys.empty()) { return null; } else { return mKeys.front(); } } void Kleo::KeyRequester::setKeys(const std::vector &keys) { mKeys.clear(); for (auto it = keys.begin(); it != keys.end(); ++it) { if (!it->isNull()) { mKeys.push_back(*it); } } updateKeys(); } void Kleo::KeyRequester::setKey(const GpgME::Key &key) { mKeys.clear(); if (!key.isNull()) { mKeys.push_back(key); } updateKeys(); } QString Kleo::KeyRequester::fingerprint() const { if (mKeys.empty()) { return QString(); } else { return QLatin1String(mKeys.front().primaryFingerprint()); } } QStringList Kleo::KeyRequester::fingerprints() const { QStringList result; for (auto it = mKeys.begin(); it != mKeys.end(); ++it) { if (!it->isNull()) { if (const char *fpr = it->primaryFingerprint()) { result.push_back(QLatin1String(fpr)); } } } return result; } void Kleo::KeyRequester::setFingerprint(const QString &fingerprint) { startKeyListJob(QStringList(fingerprint)); } void Kleo::KeyRequester::setFingerprints(const QStringList &fingerprints) { startKeyListJob(fingerprints); } void Kleo::KeyRequester::updateKeys() { if (mKeys.empty()) { if (mComplianceIcon) { mComplianceIcon->setPixmap(QIcon::fromTheme(QStringLiteral("emblem-unavailable")).pixmap(22)); mComplianceIcon->setToolTip(QString{}); } mLabel->clear(); return; } if (mKeys.size() > 1) { setMultipleKeysEnabled(true); } QStringList labelTexts; QString toolTipText; for (std::vector::const_iterator it = mKeys.begin(); it != mKeys.end(); ++it) { if (it->isNull()) { continue; } const QString fpr = QLatin1String(it->primaryFingerprint()); labelTexts.push_back(fpr.right(8)); toolTipText += fpr.right(8) + QLatin1String(": "); if (const char *uid = it->userID(0).id()) { if (it->protocol() == GpgME::OpenPGP) { toolTipText += QString::fromUtf8(uid); } else { toolTipText += Kleo::DN(uid).prettyDN(); } } else { toolTipText += xi18n("unknown"); } toolTipText += QLatin1Char('\n'); } if (mComplianceIcon) { if (Kleo::all_of(mKeys, &Kleo::DeVSCompliance::keyIsCompliant)) { mComplianceIcon->setPixmap(QIcon::fromTheme(QStringLiteral("emblem-success")).pixmap(22)); mComplianceIcon->setToolTip(DeVSCompliance::name(true)); } else { - mComplianceIcon->setPixmap(QIcon::fromTheme(QStringLiteral("emblem-information")).pixmap(22)); + mComplianceIcon->setPixmap(QIcon::fromTheme(QStringLiteral("emblem-warning")).pixmap(22)); mComplianceIcon->setToolTip(DeVSCompliance::name(false)); } } mLabel->setText(labelTexts.join(QLatin1String(", "))); mLabel->setToolTip(toolTipText); } #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( "

An error occurred while fetching " "the keys from the backend:

" "

%1

", QString::fromLocal8Bit(err.asString())); KMessageBox::error(parent, msg, i18n("Key Listing Failed")); } #endif // __KLEO_UI_SHOW_KEY_LIST_ERROR_H__ void Kleo::KeyRequester::startKeyListJob(const QStringList &fingerprints) { if (!mSMIMEBackend && !mOpenPGPBackend) { return; } mTmpKeys.clear(); mJobs = 0; unsigned int count = 0; for (QStringList::const_iterator it = fingerprints.begin(); it != fingerprints.end(); ++it) { if (!(*it).trimmed().isEmpty()) { ++count; } } if (!count) { // don't fall into the trap that an empty pattern means // "return all keys" :) setKey(GpgME::Key::null); return; } if (mOpenPGPBackend) { KeyListJob *job = mOpenPGPBackend->keyListJob(false); // local, no sigs if (!job) { KMessageBox::error(this, i18n("The OpenPGP backend does not support listing keys. " "Check your installation."), i18n("Key Listing Failed")); } else { connect(job, &KeyListJob::result, this, &SigningKeyRequester::slotKeyListResult); connect(job, &KeyListJob::nextKey, this, &SigningKeyRequester::slotNextKey); const GpgME::Error err = job->start(fingerprints, mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && !(mKeyUsage & Kleo::KeySelectionDialog::PublicKeys)); if (err) { showKeyListError(this, err); } else { ++mJobs; } } } if (mSMIMEBackend) { KeyListJob *job = mSMIMEBackend->keyListJob(false); // local, no sigs if (!job) { KMessageBox::error(this, i18n("The S/MIME backend does not support listing keys. " "Check your installation."), i18n("Key Listing Failed")); } else { connect(job, &KeyListJob::result, this, &SigningKeyRequester::slotKeyListResult); connect(job, &KeyListJob::nextKey, this, &SigningKeyRequester::slotNextKey); const GpgME::Error err = job->start(fingerprints, mKeyUsage & Kleo::KeySelectionDialog::SecretKeys && !(mKeyUsage & Kleo::KeySelectionDialog::PublicKeys)); if (err) { showKeyListError(this, err); } else { ++mJobs; } } } if (mJobs > 0) { mEraseButton->setEnabled(false); mDialogButton->setEnabled(false); } } void Kleo::KeyRequester::slotNextKey(const GpgME::Key &key) { if (!key.isNull()) { mTmpKeys.push_back(key); } } void Kleo::KeyRequester::slotKeyListResult(const GpgME::KeyListResult &res) { if (res.error()) { showKeyListError(this, res.error()); } if (--mJobs <= 0) { mEraseButton->setEnabled(true); mDialogButton->setEnabled(true); setKeys(mTmpKeys); mTmpKeys.clear(); } } void Kleo::KeyRequester::slotDialogButtonClicked() { KeySelectionDialog *dlg = mKeys.empty() ? new KeySelectionDialog(mDialogCaption, mDialogMessage, mInitialQuery, mKeyUsage, mMulti, false, this) : new KeySelectionDialog(mDialogCaption, mDialogCaption, mKeys, mKeyUsage, mMulti, false, this); if (dlg->exec() == QDialog::Accepted) { if (mMulti) { setKeys(dlg->selectedKeys()); } else { setKey(dlg->selectedKey()); } Q_EMIT changed(); } delete dlg; } void Kleo::KeyRequester::slotEraseButtonClicked() { if (!mKeys.empty()) { Q_EMIT changed(); } mKeys.clear(); updateKeys(); } void Kleo::KeyRequester::setDialogCaption(const QString &caption) { mDialogCaption = caption; } void Kleo::KeyRequester::setDialogMessage(const QString &msg) { mDialogMessage = msg; } bool Kleo::KeyRequester::isMultipleKeysEnabled() const { return mMulti; } void Kleo::KeyRequester::setMultipleKeysEnabled(bool multi) { if (multi == mMulti) { return; } if (!multi && !mKeys.empty()) { mKeys.erase(mKeys.begin() + 1, mKeys.end()); } mMulti = multi; updateKeys(); } unsigned int Kleo::KeyRequester::allowedKeys() const { return mKeyUsage; } void Kleo::KeyRequester::setAllowedKeys(unsigned int keyUsage) { mKeyUsage = keyUsage; mOpenPGPBackend = nullptr; mSMIMEBackend = nullptr; if (mKeyUsage & KeySelectionDialog::OpenPGPKeys) { mOpenPGPBackend = openpgp(); } if (mKeyUsage & KeySelectionDialog::SMIMEKeys) { mSMIMEBackend = smime(); } if (mOpenPGPBackend && !mSMIMEBackend) { mDialogCaption = i18n("OpenPGP Key Selection"); mDialogMessage = i18n("Please select an OpenPGP key to use."); } else if (!mOpenPGPBackend && mSMIMEBackend) { mDialogCaption = i18n("S/MIME Key Selection"); mDialogMessage = i18n("Please select an S/MIME key to use."); } else { mDialogCaption = i18n("Key Selection"); mDialogMessage = i18n("Please select an (OpenPGP or S/MIME) key to use."); } } QPushButton *Kleo::KeyRequester::dialogButton() { return mDialogButton; } QPushButton *Kleo::KeyRequester::eraseButton() { return mEraseButton; } static inline unsigned int foo(bool openpgp, bool smime, bool trusted, bool valid) { unsigned int result = 0; if (openpgp) { result |= Kleo::KeySelectionDialog::OpenPGPKeys; } if (smime) { result |= Kleo::KeySelectionDialog::SMIMEKeys; } if (trusted) { result |= Kleo::KeySelectionDialog::TrustedKeys; } if (valid) { result |= Kleo::KeySelectionDialog::ValidKeys; } return result; } static inline unsigned int encryptionKeyUsage(bool openpgp, bool smime, bool trusted, bool valid) { return foo(openpgp, smime, trusted, valid) | Kleo::KeySelectionDialog::EncryptionKeys | Kleo::KeySelectionDialog::PublicKeys; } static inline unsigned int signingKeyUsage(bool openpgp, bool smime, bool trusted, bool valid) { return foo(openpgp, smime, trusted, valid) | Kleo::KeySelectionDialog::SigningKeys | Kleo::KeySelectionDialog::SecretKeys; } Kleo::EncryptionKeyRequester::EncryptionKeyRequester(bool multi, unsigned int proto, QWidget *parent, bool onlyTrusted, bool onlyValid) : KeyRequester(encryptionKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid), multi, parent) , d(nullptr) { } Kleo::EncryptionKeyRequester::EncryptionKeyRequester(QWidget *parent) : KeyRequester(0, false, parent) , d(nullptr) { } Kleo::EncryptionKeyRequester::~EncryptionKeyRequester() { } void Kleo::EncryptionKeyRequester::setAllowedKeys(unsigned int proto, bool onlyTrusted, bool onlyValid) { KeyRequester::setAllowedKeys(encryptionKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid)); } Kleo::SigningKeyRequester::SigningKeyRequester(bool multi, unsigned int proto, QWidget *parent, bool onlyTrusted, bool onlyValid) : KeyRequester(signingKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid), multi, parent) , d(nullptr) { } Kleo::SigningKeyRequester::SigningKeyRequester(QWidget *parent) : KeyRequester(0, false, parent) , d(nullptr) { } Kleo::SigningKeyRequester::~SigningKeyRequester() { } void Kleo::SigningKeyRequester::setAllowedKeys(unsigned int proto, bool onlyTrusted, bool onlyValid) { KeyRequester::setAllowedKeys(signingKeyUsage(proto & OpenPGP, proto & SMIME, onlyTrusted, onlyValid)); } void Kleo::KeyRequester::virtual_hook(int, void *) { } void Kleo::EncryptionKeyRequester::virtual_hook(int id, void *data) { KeyRequester::virtual_hook(id, data); } void Kleo::SigningKeyRequester::virtual_hook(int id, void *data) { KeyRequester::virtual_hook(id, data); }