diff --git a/src/commands/exportsecretkeycommand.h b/src/commands/exportsecretkeycommand.h index 26e73de7a..d62c58241 100644 --- a/src/commands/exportsecretkeycommand.h +++ b/src/commands/exportsecretkeycommand.h @@ -1,86 +1,85 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/exportsecretkeycommand.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_COMMMANDS_EXPORTSECRETKEYCOMMAND_H__ #define __KLEOPATRA_COMMMANDS_EXPORTSECRETKEYCOMMAND_H__ #include #include -#include namespace Kleo { namespace Commands { class ExportSecretKeyCommand : public GnuPGProcessCommand { Q_OBJECT public: explicit ExportSecretKeyCommand(QAbstractItemView *view, KeyListController *parent); explicit ExportSecretKeyCommand(KeyListController *parent); explicit ExportSecretKeyCommand(const GpgME::Key &key); ~ExportSecretKeyCommand() override; void setFileName(const QString &fileName); QString fileName() const { return m_filename; } /* reimp */ static Restrictions restrictions() { return OnlyOneKey | NeedSecretKey; } private: bool preStartHook(QWidget *) const override; QStringList arguments() const override; QString errorCaption() const override; QString successCaption() const override; QString crashExitMessage(const QStringList &) const override; QString errorExitMessage(const QStringList &) const override; QString successMessage(const QStringList &) const override; private: mutable QString m_filename; mutable bool m_armor; }; } } #endif // __KLEOPATRA_COMMMANDS_EXPORTSECRETKEYCOMMAND_H__ diff --git a/src/commands/selftestcommand.cpp b/src/commands/selftestcommand.cpp index 86c85160f..d820303db 100644 --- a/src/commands/selftestcommand.cpp +++ b/src/commands/selftestcommand.cpp @@ -1,294 +1,293 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/selftestcommand.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "selftestcommand.h" #include "command_p.h" #include #include "kleopatra_debug.h" #ifdef Q_OS_WIN # include #endif #include #include #ifdef HAVE_KLEOPATRACLIENT_LIBRARY # include #endif #include #include #include -#include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; static const char *const components[] = { nullptr, // gpgconf "gpg", "gpg-agent", "scdaemon", "gpgsm", "dirmngr", }; static const unsigned int numComponents = sizeof components / sizeof * components; class SelfTestCommand::Private : Command::Private { friend class ::Kleo::Commands::SelfTestCommand; SelfTestCommand *q_func() const { return static_cast(q); } public: explicit Private(SelfTestCommand *qq, KeyListController *c); ~Private(); private: void init(); void ensureDialogCreated() { if (dialog) { return; } dialog = new SelfTestDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(updateRequested()), q_func(), SLOT(slotUpdateRequested())); connect(dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected())); dialog->setRunAtStartUp(runAtStartUp()); dialog->setAutomaticMode(automatic); } void ensureDialogShown() { ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } } bool runAtStartUp() const { const KConfigGroup config(KSharedConfig::openConfig(), "Self-Test"); return config.readEntry("run-at-startup", true); } void setRunAtStartUp(bool on) { KConfigGroup config(KSharedConfig::openConfig(), "Self-Test"); config.writeEntry("run-at-startup", on); } void runTests() { std::vector< std::shared_ptr > tests; #if defined(Q_OS_WIN) qCDebug(KLEOPATRA_LOG) << "Checking Windows Registry..."; tests.push_back(makeGpgProgramRegistryCheckSelfTest()); #if defined(HAVE_KLEOPATRACLIENT_LIBRARY) qCDebug(KLEOPATRA_LOG) << "Checking Ui Server connectivity..."; tests.push_back(makeUiServerConnectivitySelfTest()); #endif #endif qCDebug(KLEOPATRA_LOG) << "Checking gpg installation..."; tests.push_back(makeGpgEngineCheckSelfTest()); qCDebug(KLEOPATRA_LOG) << "Checking gpgsm installation..."; tests.push_back(makeGpgSmEngineCheckSelfTest()); qCDebug(KLEOPATRA_LOG) << "Checking gpgconf installation..."; tests.push_back(makeGpgConfEngineCheckSelfTest()); for (unsigned int i = 0; i < numComponents; ++i) { qCDebug(KLEOPATRA_LOG) << "Checking configuration of:" << components[i]; tests.push_back(makeGpgConfCheckConfigurationSelfTest(components[i])); } #ifndef Q_OS_WIN tests.push_back(makeGpgAgentConnectivitySelfTest()); #endif tests.push_back(makeLibKleopatraRcSelfTest()); if (!dialog && std::none_of(tests.cbegin(), tests.cend(), [](const std::shared_ptr &test) { return test->failed(); })) { finished(); return; } ensureDialogCreated(); dialog->clear(); dialog->addSelfTests(tests); ensureDialogShown(); } private: void slotDialogAccepted() { setRunAtStartUp(dialog->runAtStartUp()); finished(); } void slotDialogRejected() { if (automatic) { canceled = true; Command::Private::canceled(); } else { slotDialogAccepted(); } } void slotUpdateRequested() { const auto conf = QGpgME::cryptoConfig(); if (conf) { conf->clear(); } runTests(); } private: QPointer dialog; bool canceled; bool automatic; }; SelfTestCommand::Private *SelfTestCommand::d_func() { return static_cast(d.get()); } const SelfTestCommand::Private *SelfTestCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SelfTestCommand::Private::Private(SelfTestCommand *qq, KeyListController *c) : Command::Private(qq, c), dialog(), canceled(false), automatic(false) { } SelfTestCommand::Private::~Private() { } SelfTestCommand::SelfTestCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } SelfTestCommand::SelfTestCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void SelfTestCommand::Private::init() { } SelfTestCommand::~SelfTestCommand() {} void SelfTestCommand::setAutomaticMode(bool on) { d->automatic = on; if (d->dialog) { d->dialog->setAutomaticMode(on); } } bool SelfTestCommand::isCanceled() const { return d->canceled; } void SelfTestCommand::doStart() { if (d->automatic) { if (!d->runAtStartUp()) { d->finished(); return; } } else { d->ensureDialogCreated(); } d->runTests(); } void SelfTestCommand::doCancel() { d->canceled = true; if (d->dialog) { d->dialog->close(); } d->dialog = nullptr; } #undef d #undef q #include "moc_selftestcommand.cpp" diff --git a/src/crypto/decryptverifytask.cpp b/src/crypto/decryptverifytask.cpp index 33635d8e6..1559b0f80 100644 --- a/src/crypto/decryptverifytask.cpp +++ b/src/crypto/decryptverifytask.cpp @@ -1,1625 +1,1624 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifytask.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "decryptverifytask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include // Qt::escape -#include #include #include #if GPGMEPP_VERSION > 0x10B01 // > 1.11.1 # define GPGME_HAS_LEGACY_NOMDC #endif using namespace Kleo::Crypto; using namespace Kleo; using namespace GpgME; using namespace KMime::Types; namespace { static Error make_error(const gpg_err_code_t code) { return Error(gpg_error(code)); } static AuditLog auditLogFromSender(QObject *sender) { return AuditLog::fromJob(qobject_cast(sender)); } static bool addrspec_equal(const AddrSpec &lhs, const AddrSpec &rhs, Qt::CaseSensitivity cs) { return lhs.localPart.compare(rhs.localPart, cs) == 0 && lhs.domain.compare(rhs.domain, Qt::CaseInsensitive) == 0; } static bool mailbox_equal(const Mailbox &lhs, const Mailbox &rhs, Qt::CaseSensitivity cs) { return addrspec_equal(lhs.addrSpec(), rhs.addrSpec(), cs); } static std::string stripAngleBrackets(const std::string &str) { if (str.empty()) { return str; } if (str[0] == '<' && str[str.size() - 1] == '>') { return str.substr(1, str.size() - 2); } return str; } static std::string email(const UserID &uid) { if (uid.parent().protocol() == OpenPGP) { if (const char *const email = uid.email()) { return stripAngleBrackets(email); } else { return std::string(); } } Q_ASSERT(uid.parent().protocol() == CMS); if (const char *const id = uid.id()) if (*id == '<') { return stripAngleBrackets(id); } else { return DN(id)[QStringLiteral("EMAIL")].trimmed().toUtf8().constData(); } else { return std::string(); } } static Mailbox mailbox(const UserID &uid) { const std::string e = email(uid); Mailbox mbox; if (!e.empty()) { mbox.setAddress(e.c_str()); } return mbox; } static std::vector extractMailboxes(const Key &key) { std::vector res; Q_FOREACH (const UserID &id, key.userIDs()) { const Mailbox mbox = mailbox(id); if (!mbox.addrSpec().isEmpty()) { res.push_back(mbox); } } return res; } static std::vector extractMailboxes(const std::vector &signers) { std::vector res; for (const Key &i : signers) { const std::vector bxs = extractMailboxes(i); res.insert(res.end(), bxs.begin(), bxs.end()); } return res; } static bool keyContainsMailbox(const Key &key, const Mailbox &mbox) { const std::vector mbxs = extractMailboxes(key); return std::find_if(mbxs.cbegin(), mbxs.cend(), [mbox](const Mailbox &m) { return mailbox_equal(mbox, m, Qt::CaseInsensitive); }) != mbxs.cend(); } static bool keysContainMailbox(const std::vector &keys, const Mailbox &mbox) { return std::find_if(keys.cbegin(), keys.cend(), [mbox](const Key &key) { return keyContainsMailbox(key, mbox); }) != keys.cend(); } static bool relevantInDecryptVerifyContext(const VerificationResult &r) { // for D/V operations, we ignore verification results which are not errors and contain // no signatures (which means that the data was just not signed) return (r.error() && r.error().code() != GPG_ERR_DECRYPT_FAILED) || r.numSignatures() > 0; } static QString signatureSummaryToString(int summary) { if (summary & Signature::None) { return i18n("Error: Signature not verified"); } else if (summary & Signature::Valid || summary & Signature::Green) { return i18n("Good signature"); } else if (summary & Signature::KeyRevoked) { return i18n("Signing certificate was revoked"); } else if (summary & Signature::KeyExpired) { return i18n("Signing certificate is expired"); } else if (summary & Signature::KeyMissing) { return i18n("Certificate is not available"); } else if (summary & Signature::SigExpired) { return i18n("Signature expired"); } else if (summary & Signature::CrlMissing) { return i18n("CRL missing"); } else if (summary & Signature::CrlTooOld) { return i18n("CRL too old"); } else if (summary & Signature::BadPolicy) { return i18n("Bad policy"); } else if (summary & Signature::SysError) { return i18n("System error"); //### retrieve system error details? } else if (summary & Signature::Red) { return i18n("Bad signature"); }return QString(); } static QString formatValidSignatureWithTrustLevel(const UserID &id) { if (id.isNull()) { return QString(); } switch (id.validity()) { case UserID::Marginal: return i18n("The signature is valid but the trust in the certificate's validity is only marginal."); case UserID::Full: return i18n("The signature is valid and the certificate's validity is fully trusted."); case UserID::Ultimate: return i18n("The signature is valid and the certificate's validity is ultimately trusted."); case UserID::Never: return i18n("The signature is valid but the certificate's validity is not trusted."); case UserID::Unknown: return i18n("The signature is valid but the certificate's validity is unknown."); case UserID::Undefined: default: return i18n("The signature is valid but the certificate's validity is undefined."); } } static QString renderKeyLink(const QString &fpr, const QString &text) { return QStringLiteral("%2").arg(fpr, text); } static QString renderKey(const Key &key) { if (key.isNull()) { return i18n("Unknown certificate"); } if (key.primaryFingerprint() && strlen(key.primaryFingerprint()) > 16 && key.numUserIDs()) { const QString text = QStringLiteral("%1 (%2)").arg(Formatting::prettyNameAndEMail(key).toHtmlEscaped()).arg( Formatting::prettyID(QString::fromLocal8Bit(key.primaryFingerprint()).right(16).toLatin1().constData())); return renderKeyLink(QLatin1String(key.primaryFingerprint()), text); } return renderKeyLink(QLatin1String(key.primaryFingerprint()), Formatting::prettyID(key.primaryFingerprint())); } static QString renderKeyEMailOnlyNameAsFallback(const Key &key) { if (key.isNull()) { return i18n("Unknown certificate"); } const QString email = Formatting::prettyEMail(key); const QString user = !email.isEmpty() ? email : Formatting::prettyName(key); return renderKeyLink(QLatin1String(key.primaryFingerprint()), user); } static QString formatDate(const QDateTime &dt) { return QLocale().toString(dt); } static QString formatSigningInformation(const Signature &sig) { if (sig.isNull()) { return QString(); } const QDateTime dt = sig.creationTime() != 0 ? QDateTime::fromSecsSinceEpoch(sig.creationTime()) : QDateTime(); QString text; Key key = sig.key(); if (dt.isValid()) { text = i18nc("1 is a date", "Signature created on %1", formatDate(dt)) + QStringLiteral("
"); } if (key.isNull()) { return text += i18n("With unavailable certificate:") + QStringLiteral("
ID: 0x%1").arg(QString::fromLatin1(sig.fingerprint()).toUpper()); } text += i18n("With certificate:") + QStringLiteral("
") + renderKey(key); if (Kleo::gpgComplianceP("de-vs")) { text += (QStringLiteral("
") + (IS_DE_VS(sig) ? i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that a signature is compliant with that.", "The signature is VS-NfD-compliant.") : i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that a signature is not compliant with that.", "The signature is not VS-NfD-compliant."))); } return text; } static QString strikeOut(const QString &str, bool strike) { return QString(strike ? QStringLiteral("%1") : QStringLiteral("%1")).arg(str.toHtmlEscaped()); } static QString formatInputOutputLabel(const QString &input, const QString &output, bool inputDeleted, bool outputDeleted) { if (output.isEmpty()) { return strikeOut(input, inputDeleted); } return i18nc("Input file --> Output file (rarr is arrow", "%1 → %2", strikeOut(input, inputDeleted), strikeOut(output, outputDeleted)); } static bool IsErrorOrCanceled(const GpgME::Error &err) { return err || err.isCanceled(); } static bool IsErrorOrCanceled(const Result &res) { return IsErrorOrCanceled(res.error()); } static bool IsBad(const Signature &sig) { return sig.summary() & Signature::Red; } static bool IsGoodOrValid(const Signature &sig) { return (sig.summary() & Signature::Valid) || (sig.summary() & Signature::Green); } static UserID findUserIDByMailbox(const Key &key, const Mailbox &mbox) { Q_FOREACH (const UserID &id, key.userIDs()) if (mailbox_equal(mailbox(id), mbox, Qt::CaseInsensitive)) { return id; } return UserID(); } static void updateKeys(const VerificationResult &result) { // This little hack works around the problem that GnuPG / GpgME does not // provide Key information in a verification result. The Key object is // a dummy just holding the KeyID. This hack ensures that all available // keys are fetched from the backend and are populated for (const auto &sig: result.signatures()) { // Update key information sig.key(true, true); } } } class DecryptVerifyResult::SenderInfo { public: explicit SenderInfo(const Mailbox &infSender, const std::vector &signers_) : informativeSender(infSender), signers(signers_) {} const Mailbox informativeSender; const std::vector signers; bool hasInformativeSender() const { return !informativeSender.addrSpec().isEmpty(); } bool conflicts() const { return hasInformativeSender() && hasKeys() && !keysContainMailbox(signers, informativeSender); } bool hasKeys() const { return std::any_of(signers.cbegin(), signers.cend(), [](const Key &key) { return !key.isNull(); }); } std::vector signerMailboxes() const { return extractMailboxes(signers); } }; namespace { static Task::Result::VisualCode codeForVerificationResult(const VerificationResult &res) { if (res.isNull()) { return Task::Result::NeutralSuccess; } const std::vector sigs = res.signatures(); if (sigs.empty()) { return Task::Result::Warning; } if (std::find_if(sigs.begin(), sigs.end(), IsBad) != sigs.end()) { return Task::Result::Danger; } if ((size_t)std::count_if(sigs.begin(), sigs.end(), IsGoodOrValid) == sigs.size()) { return Task::Result::AllGood; } return Task::Result::Warning; } static QString formatVerificationResultOverview(const VerificationResult &res, const DecryptVerifyResult::SenderInfo &info) { if (res.isNull()) { return QString(); } const Error err = res.error(); if (err.isCanceled()) { return i18n("Verification canceled."); } else if (err) { return i18n("Verification failed: %1.", QString::fromLocal8Bit(err.asString()).toHtmlEscaped()); } const std::vector sigs = res.signatures(); if (sigs.empty()) { return i18n("No signatures found."); } const uint bad = std::count_if(sigs.cbegin(), sigs.cend(), IsBad); if (bad > 0) { return i18np("Invalid signature.", "%1 invalid signatures.", bad); } const uint warn = std::count_if(sigs.cbegin(), sigs.cend(), [](const Signature &sig) { return !IsGoodOrValid(sig); }); if (warn == sigs.size()) { return i18np("The data could not be verified.", "%1 signatures could not be verified.", warn); } //Good signature: QString text; if (sigs.size() == 1) { text = i18n("Valid signature by %1", renderKeyEMailOnlyNameAsFallback(sigs[0].key())); if (info.conflicts()) text += i18n("
Warning: The sender's mail address is not stored in the %1 used for signing.", renderKeyLink(QLatin1String(sigs[0].key().primaryFingerprint()), i18n("certificate"))); } else { text = i18np("Valid signature.", "%1 valid signatures.", sigs.size()); if (info.conflicts()) { text += i18n("
Warning: The sender's mail address is not stored in the certificates used for signing."); } } return text; } static QString formatDecryptionResultOverview(const DecryptionResult &result, const QString &errorString = QString()) { const Error err = result.error(); if (err.isCanceled()) { return i18n("Decryption canceled."); } #ifdef GPGME_HAS_LEGACY_NOMDC else if (result.isLegacyCipherNoMDC()) { return i18n("Decryption failed: %1.", i18n("No integrity protection (MDC).")); } #endif else if (!errorString.isEmpty()) { return i18n("Decryption failed: %1.", errorString.toHtmlEscaped()); } else if (err) { return i18n("Decryption failed: %1.", QString::fromLocal8Bit(err.asString()).toHtmlEscaped()); } return i18n("Decryption succeeded."); } static QString formatSignature(const Signature &sig, const DecryptVerifyResult::SenderInfo &info) { if (sig.isNull()) { return QString(); } const QString text = formatSigningInformation(sig) + QLatin1String("
"); const Key key = sig.key(); // Green if (sig.summary() & Signature::Valid) { const UserID id = findUserIDByMailbox(key, info.informativeSender); return text + formatValidSignatureWithTrustLevel(!id.isNull() ? id : key.userID(0)); } // Red if ((sig.summary() & Signature::Red)) { const QString ret = text + i18n("The signature is invalid: %1", signatureSummaryToString(sig.summary())); if (sig.summary() & Signature::SysError) { return ret + QStringLiteral(" (%1)").arg(QString::fromLocal8Bit(sig.status().asString())); } return ret; } // Key missing if ((sig.summary() & Signature::KeyMissing)) { return text + i18n("You can search the certificate on a keyserver or import it from a file."); } // Yellow if ((sig.validity() & Signature::Validity::Undefined) || (sig.validity() & Signature::Validity::Unknown) || (sig.summary() == Signature::Summary::None)) { return text + (key.protocol() == OpenPGP ? i18n("The used key is not certified by you or any trusted person.") : i18n("The used certificate is not certified by a trustworthy Certificate Authority or the Certificate Authority is unknown.")); } // Catch all fall through const QString ret = text + i18n("The signature is invalid: %1", signatureSummaryToString(sig.summary())); if (sig.summary() & Signature::SysError) { return ret + QStringLiteral(" (%1)").arg(QString::fromLocal8Bit(sig.status().asString())); } return ret; } static QStringList format(const std::vector &mbxs) { QStringList res; std::transform(mbxs.cbegin(), mbxs.cend(), std::back_inserter(res), [](const Mailbox &mbox) { return mbox.prettyAddress(); }); return res; } static QString formatVerificationResultDetails(const VerificationResult &res, const DecryptVerifyResult::SenderInfo &info, const QString &errorString) { if ((res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty()) { return i18n("Input error: %1", errorString); } const std::vector sigs = res.signatures(); QString details; for (const Signature &sig : sigs) { details += formatSignature(sig, info) + QLatin1Char('\n'); } details = details.trimmed(); details.replace(QLatin1Char('\n'), QStringLiteral("

")); if (info.conflicts()) { details += i18n("

The sender's address %1 is not stored in the certificate. Stored: %2

", info.informativeSender.prettyAddress(), format(info.signerMailboxes()).join(i18nc("separator for a list of e-mail addresses", ", "))); } return details; } static QString formatDecryptionResultDetails(const DecryptionResult &res, const std::vector &recipients, const QString &errorString, bool isSigned, const QPointer &task) { QString details; if ((res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty()) { return i18n("Input error: %1", errorString); } if (Kleo::gpgComplianceP("de-vs")) { details += ((IS_DE_VS(res) ? i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that the decryption is compliant with that.", "The decryption is VS-NfD-compliant.") : i18nc("VS-NfD-conforming is a German standard for restricted documents for which special restrictions about algorithms apply. The string states that the decryption is compliant with that.", "The decryption is not VS-NfD-compliant.")) + QStringLiteral("
")); } if (res.fileName()) { const auto decVerifyTask = qobject_cast (task.data()); if (decVerifyTask) { const auto embedFileName = QString::fromUtf8(res.fileName()).toHtmlEscaped(); if (embedFileName != decVerifyTask->outputLabel()) { details += i18n("Embedded file name: '%1'", embedFileName); details += QStringLiteral("
"); } } } if (res.isNull() || !res.error() || res.error().isCanceled()) { if (!isSigned) { return details + i18n("Note: You cannot be sure who encrypted this message as it is not signed."); } return details; } if (recipients.empty() && res.numRecipients() > 0) { return details + QLatin1String("") + i18np("One unknown recipient.", "%1 unknown recipients.", res.numRecipients()) + QLatin1String(""); } #ifdef GPGME_HAS_LEGACY_NOMDC if (res.isLegacyCipherNoMDC()) { details += i18nc("Integrity protection was missing because an old cipher was used.", "Hint: If this file was encrypted before the year 2003 it is " "likely that the file is legitimate. This is because back " "then integrity protection was not widely used.") + QStringLiteral("

") + i18nc("The user is offered to force decrypt a non integrity protected message. With the strong advice to re-encrypt it.", "If you are confident that the file was not manipulated you should re-encrypt it after you have forced the decryption.") + QStringLiteral("

"); } #endif if (!recipients.empty()) { details += i18np("Recipient:", "Recipients:", res.numRecipients()); if (res.numRecipients() == 1) { return details + QLatin1Char(' ') + renderKey(recipients.front()); } details += QLatin1String("
    "); for (const Key &key : recipients) { details += QLatin1String("
  • ") + renderKey(key) + QLatin1String("
  • "); } if (recipients.size() < res.numRecipients()) details += QLatin1String("
  • ") + i18np("One unknown recipient", "%1 unknown recipients", res.numRecipients() - recipients.size()) + QLatin1String("
  • "); details += QLatin1String("
"); } return details; } static QString formatDecryptVerifyResultOverview(const DecryptionResult &dr, const VerificationResult &vr, const DecryptVerifyResult::SenderInfo &info) { if (IsErrorOrCanceled(dr) || !relevantInDecryptVerifyContext(vr)) { return formatDecryptionResultOverview(dr); } return formatVerificationResultOverview(vr, info); } static QString formatDecryptVerifyResultDetails(const DecryptionResult &dr, const VerificationResult &vr, const std::vector &recipients, const DecryptVerifyResult::SenderInfo &info, const QString &errorString, const QPointer &task) { const QString drDetails = formatDecryptionResultDetails(dr, recipients, errorString, relevantInDecryptVerifyContext(vr), task); if (IsErrorOrCanceled(dr) || !relevantInDecryptVerifyContext(vr)) { return drDetails; } return drDetails + (drDetails.isEmpty() ? QString() : QStringLiteral("
")) + formatVerificationResultDetails(vr, info, errorString); } } // anon namespace class DecryptVerifyResult::Private { DecryptVerifyResult *const q; public: Private(DecryptVerifyOperation type, const VerificationResult &vr, const DecryptionResult &dr, const QByteArray &stuff, int errCode, const QString &errString, const QString &input, const QString &output, const AuditLog &auditLog, Task *parentTask, const Mailbox &informativeSender, DecryptVerifyResult *qq) : q(qq), m_type(type), m_verificationResult(vr), m_decryptionResult(dr), m_stuff(stuff), m_error(errCode), m_errorString(errString), m_inputLabel(input), m_outputLabel(output), m_auditLog(auditLog), m_parentTask(QPointer(parentTask)), m_informativeSender(informativeSender) { } QString label() const { return formatInputOutputLabel(m_inputLabel, m_outputLabel, false, q->hasError()); } DecryptVerifyResult::SenderInfo makeSenderInfo() const; bool isDecryptOnly() const { return m_type == Decrypt; } bool isVerifyOnly() const { return m_type == Verify; } bool isDecryptVerify() const { return m_type == DecryptVerify; } DecryptVerifyOperation m_type; VerificationResult m_verificationResult; DecryptionResult m_decryptionResult; QByteArray m_stuff; int m_error; QString m_errorString; QString m_inputLabel; QString m_outputLabel; const AuditLog m_auditLog; QPointer m_parentTask; const Mailbox m_informativeSender; }; DecryptVerifyResult::SenderInfo DecryptVerifyResult::Private::makeSenderInfo() const { return SenderInfo(m_informativeSender, KeyCache::instance()->findSigners(m_verificationResult)); } std::shared_ptr AbstractDecryptVerifyTask::fromDecryptResult(const DecryptionResult &dr, const QByteArray &plaintext, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Decrypt, VerificationResult(), dr, plaintext, 0, QString(), inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromDecryptResult(const GpgME::Error &err, const QString &what, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Decrypt, VerificationResult(), DecryptionResult(err), QByteArray(), err.code(), what, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromDecryptVerifyResult(const DecryptionResult &dr, const VerificationResult &vr, const QByteArray &plaintext, const AuditLog &auditLog) { int err = dr.error() ? dr.error().code() : vr.error().code(); return std::shared_ptr(new DecryptVerifyResult( DecryptVerify, vr, dr, plaintext, err, QString(), inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromDecryptVerifyResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( DecryptVerify, VerificationResult(), DecryptionResult(err), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const VerificationResult &vr, const QByteArray &plaintext, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Verify, vr, DecryptionResult(), plaintext, 0, QString(), inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Verify, VerificationResult(err), DecryptionResult(), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromVerifyDetachedResult(const VerificationResult &vr, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Verify, vr, DecryptionResult(), QByteArray(), 0, QString(), inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromVerifyDetachedResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog) { return std::shared_ptr(new DecryptVerifyResult( Verify, VerificationResult(err), DecryptionResult(), QByteArray(), err.code(), details, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } DecryptVerifyResult::DecryptVerifyResult(DecryptVerifyOperation type, const VerificationResult &vr, const DecryptionResult &dr, const QByteArray &stuff, int errCode, const QString &errString, const QString &inputLabel, const QString &outputLabel, const AuditLog &auditLog, Task *parentTask, const Mailbox &informativeSender) : Task::Result(), d(new Private(type, vr, dr, stuff, errCode, errString, inputLabel, outputLabel, auditLog, parentTask, informativeSender, this)) { } QString DecryptVerifyResult::overview() const { QString ov; if (d->isDecryptOnly()) { ov += formatDecryptionResultOverview(d->m_decryptionResult); } else if (d->isVerifyOnly()) { ov += formatVerificationResultOverview(d->m_verificationResult, d->makeSenderInfo()); } else { ov += formatDecryptVerifyResultOverview(d->m_decryptionResult, d->m_verificationResult, d->makeSenderInfo()); } if (ov.size() + d->label().size() > 120) { // Avoid ugly breaks ov = QStringLiteral("
") + ov; } return i18nc("label: result example: foo.sig: Verification failed. ", "%1: %2", d->label(), ov); } QString DecryptVerifyResult::details() const { if (d->isDecryptOnly()) { return formatDecryptionResultDetails(d->m_decryptionResult, KeyCache::instance()->findRecipients(d->m_decryptionResult), errorString(), false, d->m_parentTask); } if (d->isVerifyOnly()) { return formatVerificationResultDetails(d->m_verificationResult, d->makeSenderInfo(), errorString()); } return formatDecryptVerifyResultDetails(d->m_decryptionResult, d->m_verificationResult, KeyCache::instance()->findRecipients( d->m_decryptionResult), d->makeSenderInfo(), errorString(), d->m_parentTask); } bool DecryptVerifyResult::hasError() const { return d->m_error != 0; } int DecryptVerifyResult::errorCode() const { return d->m_error; } QString DecryptVerifyResult::errorString() const { return d->m_errorString; } AuditLog DecryptVerifyResult::auditLog() const { return d->m_auditLog; } QPointer DecryptVerifyResult::parentTask() const { return d->m_parentTask; } Task::Result::VisualCode DecryptVerifyResult::code() const { if ((d->m_type == DecryptVerify || d->m_type == Verify) && relevantInDecryptVerifyContext(verificationResult())) { return codeForVerificationResult(verificationResult()); } return hasError() ? NeutralError : NeutralSuccess; } GpgME::VerificationResult DecryptVerifyResult::verificationResult() const { return d->m_verificationResult; } GpgME::DecryptionResult DecryptVerifyResult::decryptionResult() const { return d->m_decryptionResult; } class AbstractDecryptVerifyTask::Private { public: Mailbox informativeSender; }; AbstractDecryptVerifyTask::AbstractDecryptVerifyTask(QObject *parent) : Task(parent), d(new Private) {} AbstractDecryptVerifyTask::~AbstractDecryptVerifyTask() {} Mailbox AbstractDecryptVerifyTask::informativeSender() const { return d->informativeSender; } void AbstractDecryptVerifyTask::setInformativeSender(const Mailbox &sender) { d->informativeSender = sender; } class DecryptVerifyTask::Private { DecryptVerifyTask *const q; public: explicit Private(DecryptVerifyTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol), m_ignoreMDCError(false) {} void slotResult(const DecryptionResult &, const VerificationResult &, const QByteArray &); void registerJob(QGpgME::DecryptVerifyJob *job) { q->connect(job, SIGNAL(result(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)), q, SLOT(slotResult(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray))); q->connect(job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); } void emitResult(const std::shared_ptr &result); std::shared_ptr m_input; std::shared_ptr m_output; const QGpgME::Protocol *m_backend; Protocol m_protocol; bool m_ignoreMDCError; }; void DecryptVerifyTask::Private::emitResult(const std::shared_ptr &result) { q->emitResult(result); Q_EMIT q->decryptVerifyResult(result); } void DecryptVerifyTask::Private::slotResult(const DecryptionResult &dr, const VerificationResult &vr, const QByteArray &plainText) { updateKeys(vr); { std::stringstream ss; ss << dr << '\n' << vr; qCDebug(KLEOPATRA_LOG) << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender(q->sender()); if (dr.error().code() || vr.error().code()) { m_output->cancel(); } else { try { kleo_assert(!dr.isNull() || !vr.isNull()); m_output->finalize(); } catch (const GpgME::Exception &e) { emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } catch (const std::exception &e) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog)); return; } } const int drErr = dr.error().code(); const QString errorString = m_output->errorString(); if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) || m_output->failed()) { emitResult(q->fromDecryptResult(drErr ? dr.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog)); return; } emitResult(q->fromDecryptVerifyResult(dr, vr, plainText, auditLog)); } DecryptVerifyTask::DecryptVerifyTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this)) { } DecryptVerifyTask::~DecryptVerifyTask() { } void DecryptVerifyTask::setInput(const std::shared_ptr &input) { d->m_input = input; kleo_assert(d->m_input && d->m_input->ioDevice()); } void DecryptVerifyTask::setOutput(const std::shared_ptr &output) { d->m_output = output; kleo_assert(d->m_output && d->m_output->ioDevice()); } void DecryptVerifyTask::setProtocol(Protocol prot) { kleo_assert(prot != UnknownProtocol); d->m_protocol = prot; d->m_backend = prot == GpgME::OpenPGP ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(d->m_backend); } void DecryptVerifyTask::autodetectProtocolFromInput() { if (!d->m_input) { return; } const Protocol p = findProtocol(d->m_input->classification()); if (p == UnknownProtocol) { throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature/ciphertext - maybe it is neither ciphertext nor a signature?"), Exception::MessageOnly); } setProtocol(p); } QString DecryptVerifyTask::label() const { return i18n("Decrypting: %1...", d->m_input->label()); } unsigned long long DecryptVerifyTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString DecryptVerifyTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString DecryptVerifyTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol DecryptVerifyTask::protocol() const { return d->m_protocol; } void DecryptVerifyTask::cancel() { } static void ensureIOOpen(QIODevice *input, QIODevice *output) { if (input && !input->isOpen()) { input->open(QIODevice::ReadOnly); } if (output && !output->isOpen()) { output->open(QIODevice::WriteOnly); } } void DecryptVerifyTask::setIgnoreMDCError(bool value) { d->m_ignoreMDCError = value; } void DecryptVerifyTask::doStart() { kleo_assert(d->m_backend); try { QGpgME::DecryptVerifyJob *const job = d->m_backend->decryptVerifyJob(); #ifdef GPGME_HAS_LEGACY_NOMDC if (d->m_ignoreMDCError) { qCDebug(KLEOPATRA_LOG) << "Modifying job to ignore MDC errors."; auto ctx = QGpgME::Job::context(job); if (!ctx) { qCWarning(KLEOPATRA_LOG) << "Failed to get context for job"; } else { const auto err = ctx->setFlag("ignore-mdc-error", "1"); if (err) { qCWarning(KLEOPATRA_LOG) << "Failed to set ignore mdc errors" << err.asString(); } } } #endif kleo_assert(job); d->registerJob(job); ensureIOOpen(d->m_input->ioDevice().get(), d->m_output->ioDevice().get()); job->start(d->m_input->ioDevice(), d->m_output->ioDevice()); } catch (const GpgME::Exception &e) { d->emitResult(fromDecryptVerifyResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog())); } catch (const std::exception &e) { d->emitResult(fromDecryptVerifyResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromDecryptVerifyResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog())); } } class DecryptTask::Private { DecryptTask *const q; public: explicit Private(DecryptTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol) {} void slotResult(const DecryptionResult &, const QByteArray &); void registerJob(QGpgME::DecryptJob *job) { q->connect(job, SIGNAL(result(GpgME::DecryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::DecryptionResult,QByteArray))); q->connect(job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); } void emitResult(const std::shared_ptr &result); std::shared_ptr m_input; std::shared_ptr m_output; const QGpgME::Protocol *m_backend; Protocol m_protocol; }; void DecryptTask::Private::emitResult(const std::shared_ptr &result) { q->emitResult(result); Q_EMIT q->decryptVerifyResult(result); } void DecryptTask::Private::slotResult(const DecryptionResult &result, const QByteArray &plainText) { { std::stringstream ss; ss << result; qCDebug(KLEOPATRA_LOG) << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender(q->sender()); if (result.error().code()) { m_output->cancel(); } else { try { kleo_assert(!result.isNull()); m_output->finalize(); } catch (const GpgME::Exception &e) { emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } catch (const std::exception &e) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog)); return; } } const int drErr = result.error().code(); const QString errorString = m_output->errorString(); if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) || m_output->failed()) { emitResult(q->fromDecryptResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog)); return; } emitResult(q->fromDecryptResult(result, plainText, auditLog)); } DecryptTask::DecryptTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this)) { } DecryptTask::~DecryptTask() { } void DecryptTask::setInput(const std::shared_ptr &input) { d->m_input = input; kleo_assert(d->m_input && d->m_input->ioDevice()); } void DecryptTask::setOutput(const std::shared_ptr &output) { d->m_output = output; kleo_assert(d->m_output && d->m_output->ioDevice()); } void DecryptTask::setProtocol(Protocol prot) { kleo_assert(prot != UnknownProtocol); d->m_protocol = prot; d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(d->m_backend); } void DecryptTask::autodetectProtocolFromInput() { if (!d->m_input) { return; } const Protocol p = findProtocol(d->m_input->classification()); if (p == UnknownProtocol) { throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this was S/MIME- or OpenPGP-encrypted - maybe it is not ciphertext at all?"), Exception::MessageOnly); } setProtocol(p); } QString DecryptTask::label() const { return i18n("Decrypting: %1...", d->m_input->label()); } unsigned long long DecryptTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString DecryptTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString DecryptTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol DecryptTask::protocol() const { return d->m_protocol; } void DecryptTask::cancel() { } void DecryptTask::doStart() { kleo_assert(d->m_backend); try { QGpgME::DecryptJob *const job = d->m_backend->decryptJob(); kleo_assert(job); d->registerJob(job); ensureIOOpen(d->m_input->ioDevice().get(), d->m_output->ioDevice().get()); job->start(d->m_input->ioDevice(), d->m_output->ioDevice()); } catch (const GpgME::Exception &e) { d->emitResult(fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog())); } catch (const std::exception &e) { d->emitResult(fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog())); } } class VerifyOpaqueTask::Private { VerifyOpaqueTask *const q; public: explicit Private(VerifyOpaqueTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol) {} void slotResult(const VerificationResult &, const QByteArray &); void registerJob(QGpgME::VerifyOpaqueJob *job) { q->connect(job, SIGNAL(result(GpgME::VerificationResult,QByteArray)), q, SLOT(slotResult(GpgME::VerificationResult,QByteArray))); q->connect(job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); } void emitResult(const std::shared_ptr &result); std::shared_ptr m_input; std::shared_ptr m_output; const QGpgME::Protocol *m_backend; Protocol m_protocol; }; void VerifyOpaqueTask::Private::emitResult(const std::shared_ptr &result) { q->emitResult(result); Q_EMIT q->decryptVerifyResult(result); } void VerifyOpaqueTask::Private::slotResult(const VerificationResult &result, const QByteArray &plainText) { updateKeys(result); { std::stringstream ss; ss << result; qCDebug(KLEOPATRA_LOG) << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender(q->sender()); if (result.error().code()) { m_output->cancel(); } else { try { kleo_assert(!result.isNull()); m_output->finalize(); } catch (const GpgME::Exception &e) { emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } catch (const std::exception &e) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog)); return; } } const int drErr = result.error().code(); const QString errorString = m_output->errorString(); if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) || m_output->failed()) { emitResult(q->fromDecryptResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog)); return; } emitResult(q->fromVerifyOpaqueResult(result, plainText, auditLog)); } VerifyOpaqueTask::VerifyOpaqueTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this)) { } VerifyOpaqueTask::~VerifyOpaqueTask() { } void VerifyOpaqueTask::setInput(const std::shared_ptr &input) { d->m_input = input; kleo_assert(d->m_input && d->m_input->ioDevice()); } void VerifyOpaqueTask::setOutput(const std::shared_ptr &output) { d->m_output = output; kleo_assert(d->m_output && d->m_output->ioDevice()); } void VerifyOpaqueTask::setProtocol(Protocol prot) { kleo_assert(prot != UnknownProtocol); d->m_protocol = prot; d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(d->m_backend); } void VerifyOpaqueTask::autodetectProtocolFromInput() { if (!d->m_input) { return; } const Protocol p = findProtocol(d->m_input->classification()); if (p == UnknownProtocol) { throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly); } setProtocol(p); } QString VerifyOpaqueTask::label() const { return i18n("Verifying: %1...", d->m_input->label()); } unsigned long long VerifyOpaqueTask::inputSize() const { return d->m_input ? d->m_input->size() : 0; } QString VerifyOpaqueTask::inputLabel() const { return d->m_input ? d->m_input->label() : QString(); } QString VerifyOpaqueTask::outputLabel() const { return d->m_output ? d->m_output->label() : QString(); } Protocol VerifyOpaqueTask::protocol() const { return d->m_protocol; } void VerifyOpaqueTask::cancel() { } void VerifyOpaqueTask::doStart() { kleo_assert(d->m_backend); try { QGpgME::VerifyOpaqueJob *const job = d->m_backend->verifyOpaqueJob(); kleo_assert(job); d->registerJob(job); ensureIOOpen(d->m_input->ioDevice().get(), d->m_output ? d->m_output->ioDevice().get() : nullptr); job->start(d->m_input->ioDevice(), d->m_output ? d->m_output->ioDevice() : std::shared_ptr()); } catch (const GpgME::Exception &e) { d->emitResult(fromVerifyOpaqueResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog())); } catch (const std::exception &e) { d->emitResult(fromVerifyOpaqueResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromVerifyOpaqueResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog())); } } class VerifyDetachedTask::Private { VerifyDetachedTask *const q; public: explicit Private(VerifyDetachedTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol) {} void slotResult(const VerificationResult &); void registerJob(QGpgME::VerifyDetachedJob *job) { q->connect(job, SIGNAL(result(GpgME::VerificationResult)), q, SLOT(slotResult(GpgME::VerificationResult))); q->connect(job, SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); } void emitResult(const std::shared_ptr &result); std::shared_ptr m_input, m_signedData; const QGpgME::Protocol *m_backend; Protocol m_protocol; }; void VerifyDetachedTask::Private::emitResult(const std::shared_ptr &result) { q->emitResult(result); Q_EMIT q->decryptVerifyResult(result); } void VerifyDetachedTask::Private::slotResult(const VerificationResult &result) { updateKeys(result); { std::stringstream ss; ss << result; qCDebug(KLEOPATRA_LOG) << ss.str().c_str(); } const AuditLog auditLog = auditLogFromSender(q->sender()); try { kleo_assert(!result.isNull()); emitResult(q->fromVerifyDetachedResult(result, auditLog)); } catch (const GpgME::Exception &e) { emitResult(q->fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); } catch (const std::exception &e) { emitResult(q->fromVerifyDetachedResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); } catch (...) { emitResult(q->fromVerifyDetachedResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog)); } } VerifyDetachedTask::VerifyDetachedTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this)) { } VerifyDetachedTask::~VerifyDetachedTask() { } void VerifyDetachedTask::setInput(const std::shared_ptr &input) { d->m_input = input; kleo_assert(d->m_input && d->m_input->ioDevice()); } void VerifyDetachedTask::setSignedData(const std::shared_ptr &signedData) { d->m_signedData = signedData; kleo_assert(d->m_signedData && d->m_signedData->ioDevice()); } void VerifyDetachedTask::setProtocol(Protocol prot) { kleo_assert(prot != UnknownProtocol); d->m_protocol = prot; d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(d->m_backend); } void VerifyDetachedTask::autodetectProtocolFromInput() { if (!d->m_input) { return; } const Protocol p = findProtocol(d->m_input->classification()); if (p == UnknownProtocol) { throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly); } setProtocol(p); } unsigned long long VerifyDetachedTask::inputSize() const { return d->m_signedData ? d->m_signedData->size() : 0; } QString VerifyDetachedTask::label() const { if (d->m_signedData) { return xi18nc("Verification of a detached signature in progress. The first file contains the data." "The second file is the signature file.", "Verifying: %1 with %2...", d->m_signedData->label(), d->m_input->label()); } return i18n("Verifying signature: %1...", d->m_input->label()); } QString VerifyDetachedTask::inputLabel() const { if (d->m_signedData && d->m_input) { return xi18nc("Verification of a detached signature summary. The first file contains the data." "The second file is signature.", "Verified %1 with %2", d->m_signedData->label(), d->m_input->label()); } return d->m_input ? d->m_input->label() : QString(); } QString VerifyDetachedTask::outputLabel() const { return QString(); } Protocol VerifyDetachedTask::protocol() const { return d->m_protocol; } void VerifyDetachedTask::cancel() { } void VerifyDetachedTask::doStart() { kleo_assert(d->m_backend); try { QGpgME::VerifyDetachedJob *const job = d->m_backend->verifyDetachedJob(); kleo_assert(job); d->registerJob(job); ensureIOOpen(d->m_input->ioDevice().get(), nullptr); ensureIOOpen(d->m_signedData->ioDevice().get(), nullptr); job->start(d->m_input->ioDevice(), d->m_signedData->ioDevice()); } catch (const GpgME::Exception &e) { d->emitResult(fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog())); } catch (const std::exception &e) { d->emitResult(fromVerifyDetachedResult(make_error(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromVerifyDetachedResult(make_error(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog())); } } #include "moc_decryptverifytask.cpp" diff --git a/src/dialogs/addemaildialog.cpp b/src/dialogs/addemaildialog.cpp index bc6822272..2b333bf55 100644 --- a/src/dialogs/addemaildialog.cpp +++ b/src/dialogs/addemaildialog.cpp @@ -1,130 +1,127 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/addemaildialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2019 g10 Code GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "addemaildialog.h" #include #include -#include #include #include #include #include -#include #include #include -#include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Dialogs; class AddEmailDialog::Private { public: Private(AddEmailDialog *qq): q(qq), mAdvancedSelected(false) { auto mainLay = new QVBoxLayout(q); auto btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); mOkButton = btnBox->button(QDialogButtonBox::Ok); QObject::connect (btnBox, &QDialogButtonBox::accepted, q, [this] () { q->accept(); }); QObject::connect (btnBox, &QDialogButtonBox::rejected, q, &QDialog::reject); btnBox->addButton(i18n("Advanced"), QDialogButtonBox::HelpRole); QObject::connect (btnBox, &QDialogButtonBox::helpRequested, q, [this] () { mAdvancedSelected = true; q->accept(); }); mainLay->addStretch(-1); auto emailLay = new QHBoxLayout; auto emailLbl = new QLabel(i18n("EMail") + QLatin1Char(':')); mEmailEdit = new QLineEdit; mEmailEdit->setValidator(Validation::email()); connect(mEmailEdit, &QLineEdit::textChanged, q, [this] () { mOkButton->setEnabled(!mEmailEdit->text().isEmpty() && mEmailEdit->hasAcceptableInput()); }); emailLbl->setBuddy(mEmailEdit); emailLay->addWidget(emailLbl); emailLay->addWidget(mEmailEdit); mainLay->addLayout(emailLay); mainLay->addWidget(btnBox); mOkButton->setEnabled(!mEmailEdit->text().isEmpty() && mEmailEdit->hasAcceptableInput()); } AddEmailDialog *q; QPushButton *mOkButton; QLineEdit *mEmailEdit; bool mAdvancedSelected; }; AddEmailDialog::AddEmailDialog(QWidget *parent): QDialog(parent), d(new Private(this)) { setWindowTitle(i18n("Add New EMail")); } AddEmailDialog::~AddEmailDialog() { } void AddEmailDialog::setEmail(const QString &email) { return d->mEmailEdit->setText(email); } QString AddEmailDialog::email() const { return d->mEmailEdit->text().trimmed(); } bool AddEmailDialog::advancedSelected() { return d->mAdvancedSelected; } diff --git a/src/dialogs/certificatedetailswidget.cpp b/src/dialogs/certificatedetailswidget.cpp index 116269ebb..70f533920 100644 --- a/src/dialogs/certificatedetailswidget.cpp +++ b/src/dialogs/certificatedetailswidget.cpp @@ -1,630 +1,629 @@ /* Copyright (c) 2016 Klarälvdalens Datakonsult AB 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "certificatedetailswidget.h" #include "ui_certificatedetailswidget.h" #include "kleopatra_debug.h" #include "exportdialog.h" #include "trustchainwidget.h" #include "subkeyswidget.h" #include "weboftrustdialog.h" #include "commands/changepassphrasecommand.h" #include "commands/changeexpirycommand.h" #include "commands/certifycertificatecommand.h" #include "commands/adduseridcommand.h" #include "commands/genrevokecommand.h" #include "commands/detailscommand.h" #include "commands/dumpcertificatecommand.h" #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #define HIDE_ROW(row) \ ui.row->setVisible(false); \ ui.row##Lbl->setVisible(false); Q_DECLARE_METATYPE(GpgME::UserID) using namespace Kleo; class CertificateDetailsWidget::Private { public: Private(CertificateDetailsWidget *parent) : q(parent) {} void setupCommonProperties(); void setupPGPProperties(); void setupSMIMEProperties(); void revokeUID(const GpgME::UserID &uid); void genRevokeCert(); void certifyClicked(); void webOfTrustClicked(); void exportClicked(); void addUserID(); void changePassphrase(); void changeExpiration(); void keysMayHaveChanged(); void showTrustChainDialog(); void showMoreDetails(); void publishCertificate(); void userIDTableContextMenuRequested(const QPoint &p); QString tofuTooltipString(const GpgME::UserID &uid) const; void smimeLinkActivated(const QString &link); void setUpdatedKey(const GpgME::Key &key); void keyListDone(const GpgME::KeyListResult &, const std::vector &, const QString &, const GpgME::Error &); Ui::CertificateDetailsWidget ui; GpgME::Key key; bool updateInProgress; private: CertificateDetailsWidget *q; }; void CertificateDetailsWidget::Private::setupCommonProperties() { // TODO: Enable once implemented HIDE_ROW(publishing) const bool hasSecret = key.hasSecret(); const bool isOpenPGP = key.protocol() == GpgME::OpenPGP; // TODO: Enable once implemented const bool canRevokeUID = false; // isOpenPGP && hasSecret ui.changePassphraseBtn->setVisible(hasSecret); ui.genRevokeBtn->setVisible(isOpenPGP && hasSecret); ui.certifyBtn->setVisible(isOpenPGP && !hasSecret); ui.changeExpirationBtn->setVisible(isOpenPGP && hasSecret); ui.addUserIDBtn->setVisible(hasSecret && isOpenPGP); ui.webOfTrustBtn->setVisible(isOpenPGP); ui.hboxLayout_1->addStretch(1); ui.validFrom->setText(Kleo::Formatting::creationDateString(key)); const QString expiry = Kleo::Formatting::expirationDateString(key); ui.expires->setText(expiry.isEmpty() ? i18nc("Expires", "never") : expiry); ui.type->setText(Kleo::Formatting::type(key)); ui.fingerprint->setText(Formatting::prettyID(key.primaryFingerprint())); if (Kleo::Formatting::complianceMode().isEmpty()) { HIDE_ROW(compliance) } else { ui.complianceLbl->setText(Kleo::Formatting::complianceStringForKey(key)); } ui.userIDTable->clear(); QStringList headers = { i18n("Email"), i18n("Name"), i18n("Trust Level") }; if (canRevokeUID) { headers << QString(); } ui.userIDTable->setColumnCount(headers.count()); ui.userIDTable->setColumnWidth(0, 200); ui.userIDTable->setColumnWidth(1, 200); ui.userIDTable->setHeaderLabels(headers); const auto uids = key.userIDs(); for (unsigned int i = 0; i < uids.size(); ++i) { const auto &uid = uids[i]; auto item = new QTreeWidgetItem; const QString toolTip = tofuTooltipString(uid); item->setData(0, Qt::UserRole, QVariant::fromValue(uid)); auto pMail = Kleo::Formatting::prettyEMail(uid); auto pName = Kleo::Formatting::prettyName(uid); if (!isOpenPGP && pMail.isEmpty() && !pName.isEmpty()) { // S/MIME UserIDs are sometimes split, with one userID // containing the name another the Mail, we merge these // UID's into a single item. if (i + 1 < uids.size()) { pMail = Kleo::Formatting::prettyEMail(uids[i + 1]); // skip next uid ++i; } } if (!isOpenPGP && pMail.isEmpty() && pName.isEmpty()) { // S/MIME certificates sometimes contain urls where both // name and mail is empty. In that case we print whatever // the uid is as name. // // Can be ugly like (3:uri24:http://ca.intevation.org), but // this is better then showing an empty entry. pName = QString::fromLatin1(uid.id()); } item->setData(0, Qt::DisplayRole, pMail); item->setData(0, Qt::ToolTipRole, toolTip); item->setData(1, Qt::DisplayRole, pName); item->setData(1, Qt::ToolTipRole, toolTip); QIcon trustIcon; if (updateInProgress) { trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question")); item->setData(2, Qt::DisplayRole, i18n("Updating...")); } else { switch (uid.validity()) { case GpgME::UserID::Unknown: case GpgME::UserID::Undefined: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-question")); break; case GpgME::UserID::Never: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-error")); break; case GpgME::UserID::Marginal: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-warning")); break; case GpgME::UserID::Full: case GpgME::UserID::Ultimate: trustIcon = QIcon::fromTheme(QStringLiteral("emblem-success")); break; } item->setData(2, Qt::DisplayRole, Kleo::Formatting::validityShort(uid)); } item->setData(2, Qt::DecorationRole, trustIcon); item->setData(2, Qt::ToolTipRole, toolTip); ui.userIDTable->addTopLevelItem(item); if (canRevokeUID) { auto button = new QPushButton; button->setIcon(QIcon::fromTheme(QStringLiteral("entry-delete"))); button->setToolTip(i18n("Revoke this User ID")); button->setMaximumWidth(32); QObject::connect(button, &QPushButton::clicked, q, [this, uid]() { revokeUID(uid); }); ui.userIDTable->setItemWidget(item, 4, button); } } } void CertificateDetailsWidget::Private::revokeUID(const GpgME::UserID &uid) { Q_UNUSED(uid); qCWarning(KLEOPATRA_LOG) << "Revoking UserID is not implemented. How did you even get here?!?!"; } void CertificateDetailsWidget::Private::changeExpiration() { auto cmd = new Kleo::Commands::ChangeExpiryCommand(key); QObject::connect(cmd, &Kleo::Commands::ChangeExpiryCommand::finished, q, [this]() { ui.changeExpirationBtn->setEnabled(true); }); ui.changeExpirationBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::changePassphrase() { auto cmd = new Kleo::Commands::ChangePassphraseCommand(key); QObject::connect(cmd, &Kleo::Commands::ChangePassphraseCommand::finished, q, [this]() { ui.changePassphraseBtn->setEnabled(true); }); ui.changePassphraseBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::genRevokeCert() { auto cmd = new Kleo::Commands::GenRevokeCommand(key); QObject::connect(cmd, &Kleo::Commands::GenRevokeCommand::finished, q, [this]() { ui.genRevokeBtn->setEnabled(true); }); ui.genRevokeBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::certifyClicked() { auto cmd = new Kleo::Commands::CertifyCertificateCommand(key); QObject::connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished, q, [this]() { ui.certifyBtn->setEnabled(true); }); ui.certifyBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::webOfTrustClicked() { QScopedPointer dlg(new WebOfTrustDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::exportClicked() { QScopedPointer dlg(new ExportDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::addUserID() { auto cmd = new Kleo::Commands::AddUserIDCommand(key); QObject::connect(cmd, &Kleo::Commands::AddUserIDCommand::finished, q, [this]() { ui.addUserIDBtn->setEnabled(true); key.update(); q->setKey(key); }); ui.addUserIDBtn->setEnabled(false); cmd->start(); } void CertificateDetailsWidget::Private::keysMayHaveChanged() { auto newKey = Kleo::KeyCache::instance()->findByFingerprint(key.primaryFingerprint()); if (!newKey.isNull()) { setUpdatedKey(newKey); } } void CertificateDetailsWidget::Private::showTrustChainDialog() { QScopedPointer dlg(new TrustChainDialog(q)); dlg->setKey(key); dlg->exec(); } void CertificateDetailsWidget::Private::publishCertificate() { qCWarning(KLEOPATRA_LOG) << "publishCertificateis not implemented."; //TODO } void CertificateDetailsWidget::Private::userIDTableContextMenuRequested(const QPoint &p) { auto item = ui.userIDTable->itemAt(p); if (!item) { return; } const auto userID = item->data(0, Qt::UserRole).value(); QMenu *menu = new QMenu(q); menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-sign")), i18n("Certify ..."), q, [this, userID]() { auto cmd = new Kleo::Commands::CertifyCertificateCommand(userID); ui.userIDTable->setEnabled(false); connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished, q, [this]() { ui.userIDTable->setEnabled(true); }); cmd->start(); }); connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ui.userIDTable->viewport()->mapToGlobal(p)); } void CertificateDetailsWidget::Private::showMoreDetails() { ui.moreDetailsBtn->setEnabled(false); if (key.protocol() == GpgME::CMS) { auto cmd = new Kleo::Commands::DumpCertificateCommand(key); connect(cmd, &Kleo::Commands::DumpCertificateCommand::finished, q, [this]() { ui.moreDetailsBtn->setEnabled(true); }); cmd->setUseDialog(true); cmd->start(); } else { QScopedPointer dlg(new SubKeysDialog(q)); dlg->setKey(key); dlg->exec(); ui.moreDetailsBtn->setEnabled(true); } } QString CertificateDetailsWidget::Private::tofuTooltipString(const GpgME::UserID &uid) const { const auto tofu = uid.tofuInfo(); if (tofu.isNull()) { return QString(); } QString html = QStringLiteral(""); const auto appendRow = [&html](const QString &lbl, const QString &val) { html += QStringLiteral("" "" "" "") .arg(lbl, val); }; const auto appendHeader = [this, &html](const QString &hdr) { html += QStringLiteral("") .arg(q->palette().highlight().color().name(), q->palette().highlightedText().color().name(), hdr); }; const auto dateTime = [](long ts) { return ts == 0 ? i18n("never") : QDateTime::fromSecsSinceEpoch(ts).toString(Qt::SystemLocaleShortDate); }; appendHeader(i18n("Signing")); appendRow(i18n("First message"), dateTime(tofu.signFirst())); appendRow(i18n("Last message"), dateTime(tofu.signLast())); appendRow(i18n("Message count"), QString::number(tofu.signCount())); appendHeader(i18n("Encryption")); appendRow(i18n("First message"), dateTime(tofu.encrFirst())); appendRow(i18n("Last message"), dateTime(tofu.encrLast())); appendRow(i18n("Message count"), QString::number(tofu.encrCount())); html += QStringLiteral("
%1:%2
%3
"); // Make sure the tooltip string is different for each UserID, even if the // data are the same, otherwise the tooltip is not updated and moved when // user moves mouse from one row to another. html += QStringLiteral("").arg(QString::fromUtf8(uid.id())); return html; } void CertificateDetailsWidget::Private::setupPGPProperties() { HIDE_ROW(smimeOwner) HIDE_ROW(smimeIssuer) ui.smimeRelatedAddresses->setVisible(false); ui.trustChainDetailsBtn->setVisible(false); ui.userIDTable->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui.userIDTable, &QAbstractItemView::customContextMenuRequested, q, [this](const QPoint &p) { userIDTableContextMenuRequested(p); }); } static QString formatDNToolTip(const Kleo::DN &dn) { QString html = QStringLiteral(""); const auto appendRow = [&html, dn](const QString &lbl, const QString &attr) { const QString val = dn[attr]; if (!val.isEmpty()) { html += QStringLiteral( "" "" "").arg(lbl, val); } }; appendRow(i18n("Common Name"), QStringLiteral("CN")); appendRow(i18n("Organization"), QStringLiteral("O")); appendRow(i18n("Street"), QStringLiteral("STREET")); appendRow(i18n("City"), QStringLiteral("L")); appendRow(i18n("State"), QStringLiteral("ST")); appendRow(i18n("Country"), QStringLiteral("C")); html += QStringLiteral("
%1:%2
"); return html; } void CertificateDetailsWidget::Private::setupSMIMEProperties() { HIDE_ROW(publishing) const auto ownerId = key.userID(0); const Kleo::DN dn(ownerId.id()); const QString cn = dn[QStringLiteral("CN")]; const QString o = dn[QStringLiteral("O")]; const QString dnEmail = dn[QStringLiteral("EMAIL")]; const QString name = cn.isEmpty() ? dnEmail : cn; QString owner; if (name.isEmpty()) { owner = dn.dn(); } else if (o.isEmpty()) { owner = name; } else { owner = i18nc(" of ", "%1 of %2", name, o); } ui.smimeOwner->setText(owner); ui.smimeOwner->setTextInteractionFlags(Qt::TextBrowserInteraction); const Kleo::DN issuerDN(key.issuerName()); const QString issuerCN = issuerDN[QStringLiteral("CN")]; const QString issuer = issuerCN.isEmpty() ? QString::fromUtf8(key.issuerName()) : issuerCN; ui.smimeIssuer->setText(QStringLiteral("%1").arg(issuer)); ui.smimeIssuer->setToolTip(formatDNToolTip(issuerDN)); ui.smimeOwner->setToolTip(formatDNToolTip(dn)); } void CertificateDetailsWidget::Private::smimeLinkActivated(const QString &link) { if (link == QLatin1String("#issuerDetails")) { const auto parentKey = KeyCache::instance()->findIssuers(key, KeyCache::NoOption); if (!parentKey.size()) { return; } auto cmd = new Kleo::Commands::DetailsCommand(parentKey[0], nullptr); cmd->setParentWidget(q); cmd->start(); return; } qCWarning(KLEOPATRA_LOG) << "Unknown link activated:" << link; } CertificateDetailsWidget::CertificateDetailsWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { d->ui.setupUi(this); connect(d->ui.addUserIDBtn, &QPushButton::clicked, this, [this]() { d->addUserID(); }); connect(d->ui.changePassphraseBtn, &QPushButton::clicked, this, [this]() { d->changePassphrase(); }); connect(d->ui.genRevokeBtn, &QPushButton::clicked, this, [this]() { d->genRevokeCert(); }); connect(d->ui.changeExpirationBtn, &QPushButton::clicked, this, [this]() { d->changeExpiration(); }); connect(d->ui.smimeOwner, &QLabel::linkActivated, this, [this](const QString &link) { d->smimeLinkActivated(link); }); connect(d->ui.smimeIssuer, &QLabel::linkActivated, this, [this](const QString &link) { d->smimeLinkActivated(link); }); connect(d->ui.trustChainDetailsBtn, &QPushButton::pressed, this, [this]() { d->showTrustChainDialog(); }); connect(d->ui.moreDetailsBtn, &QPushButton::pressed, this, [this]() { d->showMoreDetails(); }); connect(d->ui.publishing, &QPushButton::pressed, this, [this]() { d->publishCertificate(); }); connect(d->ui.certifyBtn, &QPushButton::clicked, this, [this]() { d->certifyClicked(); }); connect(d->ui.webOfTrustBtn, &QPushButton::clicked, this, [this]() { d->webOfTrustClicked(); }); connect(d->ui.exportBtn, &QPushButton::clicked, this, [this]() { d->exportClicked(); }); connect(Kleo::KeyCache::instance().get(), &Kleo::KeyCache::keysMayHaveChanged, this, [this]() { d->keysMayHaveChanged(); }); } CertificateDetailsWidget::~CertificateDetailsWidget() { } void CertificateDetailsWidget::Private::keyListDone(const GpgME::KeyListResult &, const std::vector &keys, const QString &, const GpgME::Error &) { updateInProgress = false; if (keys.size() != 1) { qCWarning(KLEOPATRA_LOG) << "Invalid keylist result in update."; return; } // As we listen for keysmayhavechanged we get the update // after updating the keycache. KeyCache::mutableInstance()->insert(keys); } void CertificateDetailsWidget::Private::setUpdatedKey(const GpgME::Key &k) { key = k; setupCommonProperties(); if (key.protocol() == GpgME::OpenPGP) { setupPGPProperties(); } else { setupSMIMEProperties(); } } void CertificateDetailsWidget::setKey(const GpgME::Key &key) { if (key.protocol() == GpgME::CMS) { // For everything but S/MIME this should be quick // and we don't need to show another status. d->updateInProgress = true; } d->setUpdatedKey(key); // Run a keylistjob with full details (TOFU / Validate) QGpgME::KeyListJob *job = key.protocol() == GpgME::OpenPGP ? QGpgME::openpgp()->keyListJob(false, true, true) : QGpgME::smime()->keyListJob(false, true, true); auto ctx = QGpgME::Job::context(job); ctx->addKeyListMode(GpgME::WithTofu); // Windows QGpgME new style connect problem makes this necessary. connect(job, SIGNAL(result(GpgME::KeyListResult,std::vector,QString,GpgME::Error)), this, SLOT(keyListDone(GpgME::KeyListResult,std::vector,QString,GpgME::Error))); job->start(QStringList() << QLatin1String(key.primaryFingerprint()), key.hasSecret()); } GpgME::Key CertificateDetailsWidget::key() const { return d->key; } CertificateDetailsDialog::CertificateDetailsDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Certificate Details")); auto l = new QVBoxLayout(this); l->addWidget(new CertificateDetailsWidget(this)); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::pressed, this, &QDialog::accept); l->addWidget(bbox); readConfig(); } CertificateDetailsDialog::~CertificateDetailsDialog() { writeConfig(); } void CertificateDetailsDialog::readConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog"); const QSize size = dialog.readEntry("Size", QSize(730, 280)); if (size.isValid()) { resize(size); } } void CertificateDetailsDialog::writeConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "CertificateDetailsDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } void CertificateDetailsDialog::setKey(const GpgME::Key &key) { auto w = findChild(); Q_ASSERT(w); w->setKey(key); } GpgME::Key CertificateDetailsDialog::key() const { auto w = findChild(); Q_ASSERT(w); return w->key(); } #include "moc_certificatedetailswidget.cpp" diff --git a/src/dialogs/exportdialog.cpp b/src/dialogs/exportdialog.cpp index 80e1ff4ed..d96f5ecff 100644 --- a/src/dialogs/exportdialog.cpp +++ b/src/dialogs/exportdialog.cpp @@ -1,202 +1,199 @@ /* Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "exportdialog.h" #include "kleopatra_debug.h" #include "view/waitwidget.h" #include #include -#include -#include -#include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; class ExportWidget::Private { public: Private(ExportWidget *qq) : q(qq) {} void setupUi(); GpgME::Key key; QTextEdit *textEdit; WaitWidget *waitWidget; private: ExportWidget *q; }; void ExportWidget::Private::setupUi() { auto vlay = new QVBoxLayout(q); vlay->setContentsMargins(0, 0, 0, 0); textEdit = new QTextEdit; textEdit->setVisible(false); textEdit->setReadOnly(true); auto fixedFont = QFont(QStringLiteral("Monospace")); fixedFont.setStyleHint(QFont::TypeWriter); textEdit->setFont(fixedFont); textEdit->setReadOnly(true); vlay->addWidget(textEdit); waitWidget = new WaitWidget; waitWidget->setText(i18n("Exporting ...")); vlay->addWidget(waitWidget); } ExportWidget::ExportWidget(QWidget *parent) : QWidget(parent) , d(new Private(this)) { d->setupUi(); } ExportWidget::~ExportWidget() { } static QString injectComments(const GpgME::Key &key, const QByteArray &data) { QString ret = QString::fromUtf8(data); if (key.protocol() != GpgME::OpenPGP) { return ret; } auto overView = Formatting::toolTip(key, Formatting::Fingerprint | Formatting::UserIDs | Formatting::Issuer | Formatting::Subject | Formatting::ExpiryDates | Formatting::CertificateType | Formatting::CertificateUsage); // Fixup the HTML coming from the toolTip for our own format. overView.remove(QLatin1String("")); overView.replace(QLatin1String(""), QLatin1String("\t")); overView.replace(QLatin1String(""), QLatin1String("\n")); overView.remove(QLatin1String("")); overView.remove(QLatin1String("\n
")); overView.replace(QLatin1String("<"), QLatin1String("<")); overView.replace(QLatin1String(">"), QLatin1String(">")); auto overViewLines = overView.split(QLatin1Char('\n')); // Format comments so that they fit for RFC 4880 auto comments = QStringLiteral("Comment: "); comments += overViewLines.join(QStringLiteral("\nComment: ")) + QLatin1Char('\n'); ret.insert(37 /* -----BEGIN PGP PUBLIC KEY BLOCK-----\n */, comments); return ret; } void ExportWidget::exportResult(const GpgME::Error &err, const QByteArray &data) { d->waitWidget->setVisible(false); d->textEdit->setVisible(true); if (err) { /* Should not happen. But well,.. */ d->textEdit->setText(i18nc("%1 is error message", "Failed to export: '%1'", QString::fromLatin1(err.asString()))); } d->textEdit->setText(injectComments(d->key, data)); } void ExportWidget::setKey(const GpgME::Key &key) { d->waitWidget->setVisible(true); d->textEdit->setVisible(false); d->key = key; auto protocol = key.protocol() == GpgME::CMS ? QGpgME::smime() : QGpgME::openpgp(); auto job = protocol->publicKeyExportJob(true); /* New style connect does not work on Windows. */ connect(job, &QGpgME::ExportJob::result, this, &ExportWidget::exportResult); job->start(QStringList() << QLatin1String(key.primaryFingerprint())); } GpgME::Key ExportWidget::key() const { return d->key; } ExportDialog::ExportDialog(QWidget *parent) : QDialog(parent), mWidget(new ExportWidget(this)) { KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog"); const auto size = dialog.readEntry("Size", QSize(600, 800)); if (size.isValid()) { resize(size); } setWindowTitle(i18n("Export...")); auto l = new QVBoxLayout(this); l->addWidget(mWidget); auto bbox = new QDialogButtonBox(this); auto btn = bbox->addButton(QDialogButtonBox::Close); connect(btn, &QPushButton::pressed, this, &QDialog::accept); l->addWidget(bbox); } ExportDialog::~ExportDialog() { KConfigGroup dialog(KSharedConfig::openConfig(), "ExportDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } void ExportDialog::setKey(const GpgME::Key &key) { mWidget->setKey(key); } GpgME::Key ExportDialog::key() const { return mWidget->key(); } diff --git a/src/dialogs/lookupcertificatesdialog.cpp b/src/dialogs/lookupcertificatesdialog.cpp index 98a01e255..4f7b02462 100644 --- a/src/dialogs/lookupcertificatesdialog.cpp +++ b/src/dialogs/lookupcertificatesdialog.cpp @@ -1,260 +1,259 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/lookupcertificatesdialog.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "lookupcertificatesdialog.h" #include "ui_lookupcertificatesdialog.h" #include #include #include #include #include -#include #include #include using namespace Kleo; using namespace Kleo::Dialogs; using namespace GpgME; static const int minimalSearchTextLength = 2; class LookupCertificatesDialog::Private { friend class ::Kleo::Dialogs::LookupCertificatesDialog; LookupCertificatesDialog *const q; public: explicit Private(LookupCertificatesDialog *qq); ~Private(); private: void slotSelectionChanged() { enableDisableWidgets(); } void slotSearchTextChanged() { enableDisableWidgets(); } void slotSearchClicked() { Q_EMIT q->searchTextChanged(ui.findED->text()); } void slotDetailsClicked() { Q_ASSERT(q->selectedCertificates().size() == 1); Q_EMIT q->detailsRequested(q->selectedCertificates().front()); } void slotSaveAsClicked() { Q_EMIT q->saveAsRequested(q->selectedCertificates()); } void readConfig(); void writeConfig(); void enableDisableWidgets(); QString searchText() const { return ui.findED->text().trimmed(); } std::vector selectedCertificates() const { const QAbstractItemView *const view = ui.resultTV->view(); if (!view) { return std::vector(); } const auto *const model = dynamic_cast(view->model()); Q_ASSERT(model); const QItemSelectionModel *const sm = view->selectionModel(); Q_ASSERT(sm); return model->keys(sm->selectedRows()); } int numSelectedCertificates() const { return ui.resultTV->selectedKeys().size(); } private: bool passive; struct Ui : Ui_LookupCertificatesDialog { explicit Ui(LookupCertificatesDialog *q) : Ui_LookupCertificatesDialog() { setupUi(q); saveAsPB->hide(); // ### not yet implemented in LookupCertificatesCommand findED->setClearButtonEnabled(true); resultTV->setFlatModel(AbstractKeyListModel::createFlatKeyListModel(q)); resultTV->setHierarchicalView(false); importPB()->setText(i18n("Import")); importPB()->setEnabled(false); connect(resultTV->view(), SIGNAL(doubleClicked(QModelIndex)), importPB(), SLOT(animateClick())); findED->setFocus(); connect(selectAllPB, &QPushButton::clicked, resultTV->view(), &QTreeView::selectAll); connect(deselectAllPB, &QPushButton::clicked, resultTV->view(), &QTreeView::clearSelection); } QPushButton *importPB() const { return buttonBox->button(QDialogButtonBox::Save); } QPushButton *closePB() const { return buttonBox->button(QDialogButtonBox::Close); } } ui; }; LookupCertificatesDialog::Private::Private(LookupCertificatesDialog *qq) : q(qq), passive(false), ui(q) { connect(ui.resultTV->view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotSelectionChanged())); } LookupCertificatesDialog::Private::~Private() {} void LookupCertificatesDialog::Private::readConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "LookupCertificatesDialog"); const QSize size = dialog.readEntry("Size", QSize(600, 400)); if (size.isValid()) { q->resize(size); } } void LookupCertificatesDialog::Private::writeConfig() { KConfigGroup dialog(KSharedConfig::openConfig(), "LookupCertificatesDialog"); dialog.writeEntry("Size", q->size()); dialog.sync(); } LookupCertificatesDialog::LookupCertificatesDialog(QWidget *p, Qt::WindowFlags f) : QDialog(p, f), d(new Private(this)) { d->ui.findPB->setEnabled(false); d->readConfig(); } LookupCertificatesDialog::~LookupCertificatesDialog() { d->writeConfig(); } void LookupCertificatesDialog::setCertificates(const std::vector &certs) { d->ui.resultTV->view()->setFocus(); d->ui.resultTV->setKeys(certs); } std::vector LookupCertificatesDialog::selectedCertificates() const { return d->selectedCertificates(); } void LookupCertificatesDialog::setPassive(bool on) { if (d->passive == on) { return; } d->passive = on; d->enableDisableWidgets(); } bool LookupCertificatesDialog::isPassive() const { return d->passive; } void LookupCertificatesDialog::setSearchText(const QString &text) { d->ui.findED->setText(text); } QString LookupCertificatesDialog::searchText() const { return d->ui.findED->text(); } void LookupCertificatesDialog::accept() { Q_ASSERT(!selectedCertificates().empty()); Q_EMIT importRequested(selectedCertificates()); QDialog::accept(); } void LookupCertificatesDialog::Private::enableDisableWidgets() { // enable/disable everything except 'close', based on passive: Q_FOREACH (QObject *const o, q->children()) if (QWidget *const w = qobject_cast(o)) { w->setDisabled(passive && w != ui.closePB() && w != ui.buttonBox); } if (passive) { return; } ui.findPB->setEnabled(searchText().length() > minimalSearchTextLength); const int n = q->selectedCertificates().size(); ui.detailsPB->setEnabled(n == 1); ui.saveAsPB->setEnabled(n == 1); ui.importPB()->setEnabled(n != 0); ui.importPB()->setDefault(false); // otherwise Import becomes default button if enabled and return triggers both a search and accept() } #include "moc_lookupcertificatesdialog.cpp" diff --git a/src/dialogs/weboftrustwidget.cpp b/src/dialogs/weboftrustwidget.cpp index 0286cc839..780664252 100644 --- a/src/dialogs/weboftrustwidget.cpp +++ b/src/dialogs/weboftrustwidget.cpp @@ -1,162 +1,161 @@ /* Copyright (c) 2017 Intevation GmbH Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "weboftrustwidget.h" -#include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include "commands/command.h" #include #include using namespace Kleo; class WebOfTrustWidget::Private { public: Private(WebOfTrustWidget *qq): keyListJob(nullptr), q(qq) { certificationsTV = new QTreeView; certificationsTV->setModel(&certificationsModel); certificationsTV->setAllColumnsShowFocus(true); certificationsTV->setSelectionMode(QAbstractItemView::ExtendedSelection); auto vLay = new QVBoxLayout(q); vLay->setContentsMargins(0, 0, 0, 0); vLay->addWidget(certificationsTV); connect(certificationsTV, &QAbstractItemView::doubleClicked, q, [this] (const QModelIndex &idx) { certificationDblClicked(idx); }); } void certificationDblClicked(const QModelIndex &idx) { if (!idx.isValid()) { return; } if (!idx.parent().isValid()) { // No parent -> root item. return; } // grab the keyid const auto query = certificationsModel.data(idx.sibling(idx.row(), 0)).toString(); // Show details widget or search auto cmd = Command::commandForQuery(query); cmd->setParentWId(q->winId()); cmd->start(); } void startSignatureListing() { if (keyListJob) { return; } QGpgME::KeyListJob *const job = QGpgME::openpgp()->keyListJob(/*remote*/false, /*includeSigs*/true, /*validate*/true); if (!job) { return; } /* Old style connect here again as QGPGME newstyle connects with * default arguments don't work on windows. */ connect(job, &QGpgME::KeyListJob::result, q, &WebOfTrustWidget::signatureListingDone); connect(job, &QGpgME::KeyListJob::nextKey, q, &WebOfTrustWidget::signatureListingNextKey); job->start(QStringList(QString::fromLatin1(key.primaryFingerprint()))); keyListJob = job; } GpgME::Key key; UserIDListModel certificationsModel; QGpgME::KeyListJob *keyListJob; QTreeView *certificationsTV; private: WebOfTrustWidget *q; }; WebOfTrustWidget::WebOfTrustWidget(QWidget *parent) : QWidget(parent), d(new Private(this)) { } GpgME::Key WebOfTrustWidget::key() const { return d->key; } void WebOfTrustWidget::setKey(const GpgME::Key &key) { if (key.protocol() != GpgME::OpenPGP) { qCDebug(KLEOPATRA_LOG) << "Trust chain is only supported for CMS keys"; return; } d->key = key; d->certificationsModel.setKey(key); d->certificationsTV->expandAll(); d->certificationsTV->header()->resizeSections(QHeaderView::ResizeToContents); d->startSignatureListing(); } WebOfTrustWidget::~WebOfTrustWidget() { } void WebOfTrustWidget::signatureListingNextKey(const GpgME::Key &key) { GpgME::Key merged = key; merged.mergeWith(d->key); setKey(merged); } void WebOfTrustWidget::signatureListingDone(const GpgME::KeyListResult &result) { if (result.error()) { KMessageBox::information(this, xi18nc("@info", "An error occurred while loading the certifications: " "%1", QString::fromLocal8Bit(result.error().asString())), i18nc("@title", "Certifications Loading Failed")); } d->keyListJob = nullptr; } diff --git a/src/selftest/gpgconfcheck.cpp b/src/selftest/gpgconfcheck.cpp index be43b92be..1e26552ce 100644 --- a/src/selftest/gpgconfcheck.cpp +++ b/src/selftest/gpgconfcheck.cpp @@ -1,114 +1,112 @@ /* -*- mode: c++; c-basic-offset:4 -*- selftest/gpgconfcheck.cpp This file is part of Kleopatra, the KDE keymanager Copyright (c) 2008 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #include #include "gpgconfcheck.h" #include "implementation_p.h" #include #include #include "kleopatra_debug.h" #include -#include -#include #include #include using namespace Kleo; using namespace Kleo::_detail; namespace { class GpgConfCheck : public SelfTestImplementation { QString m_component; public: explicit GpgConfCheck(const char *component) : SelfTestImplementation(i18nc("@title", "%1 Configuration Check", component && * component ? QLatin1String(component) : QLatin1String("gpgconf"))), m_component(QLatin1String(component)) { runTest(); } void runTest() { const auto conf = QGpgME::cryptoConfig(); QString message; m_passed = true; if (!conf) { message = QStringLiteral ("Could not be started."); m_passed = false; } else if (m_component.isEmpty() && conf->componentList().empty()) { message = QStringLiteral ("Could not list components."); m_passed = false; } else if (!m_component.isEmpty()) { const auto comp = conf->component (m_component); if (!comp) { message = QStringLiteral ("Binary could not be found."); m_passed = false; } else if (comp->groupList().empty()) { // If we don't have any group it means that list-options // for this component failed. message = QStringLiteral ("The configuration file is invalid."); m_passed = false; } } if (!m_passed) { m_error = i18nc("self-test did not pass", "Failed"); m_explaination = i18n("There was an error executing the GnuPG configuration self-check for %2:\n" " %1\n" "You might want to execute \"gpgconf %3\" on the command line.\n", message, m_component.isEmpty() ? QStringLiteral("GnuPG") : m_component, QStringLiteral("--check-options ") + (m_component.isEmpty() ? QStringLiteral("") : m_component)); // To avoid modifying the l10n m_explaination.replace(QLatin1Char('\n'), QStringLiteral("
")); } } }; } std::shared_ptr Kleo::makeGpgConfCheckConfigurationSelfTest(const char *component) { return std::shared_ptr(new GpgConfCheck(component)); } diff --git a/src/utils/detail_p.h b/src/utils/detail_p.h index f48239f40..e0ed2ab89 100644 --- a/src/utils/detail_p.h +++ b/src/utils/detail_p.h @@ -1,114 +1,113 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/detail_p.h This file is part of Kleopatra, the KDE keymanager Copyright (c) 2007 Klarälvdalens Datakonsult AB Kleopatra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Kleopatra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the Qt library by Trolltech AS, Norway (or with modified versions of Qt that use the same license as Qt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than Qt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ #ifndef __KLEOPATRA_UTILS_DETAIL_P_H__ #define __KLEOPATRA_UTILS_DETAIL_P_H__ #include -#include #ifdef _WIN32 #include #endif namespace Kleo { namespace _detail { template