diff --git a/src/crypto/decryptverifyfilescontroller.cpp b/src/crypto/decryptverifyfilescontroller.cpp index 8c5645e9c..5a32aafab 100644 --- a/src/crypto/decryptverifyfilescontroller.cpp +++ b/src/crypto/decryptverifyfilescontroller.cpp @@ -1,443 +1,443 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifyfilescontroller.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "decryptverifyfilescontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include using namespace GpgME; using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; class DecryptVerifyFilesController::Private { DecryptVerifyFilesController *const q; public: static std::shared_ptr taskFromOperationWidget(const DecryptVerifyOperationWidget *w, const QString &fileName, const QDir &outDir, const std::shared_ptr &overwritePolicy); explicit Private(DecryptVerifyFilesController *qq); void slotWizardOperationPrepared(); void slotWizardCanceled(); void schedule(); void prepareWizardFromPassedFiles(); std::vector > buildTasks(const QStringList &, const std::shared_ptr &); void ensureWizardCreated(); void ensureWizardVisible(); void reportError(int err, const QString &details) { q->setLastError(err, details); q->emitDoneOrError(); } void cancelAllTasks(); QStringList m_passedFiles, m_filesAfterPreparation; QPointer m_wizard; std::vector > m_results; std::vector > m_runnableTasks, m_completedTasks; std::shared_ptr m_runningTask; bool m_errorDetected; DecryptVerifyOperation m_operation; }; // static std::shared_ptr DecryptVerifyFilesController::Private::taskFromOperationWidget(const DecryptVerifyOperationWidget *w, const QString &fileName, const QDir &outDir, const std::shared_ptr &overwritePolicy) { kleo_assert(w); std::shared_ptr task; switch (w->mode()) { case DecryptVerifyOperationWidget::VerifyDetachedWithSignature: { std::shared_ptr t(new VerifyDetachedTask); t->setInput(Input::createFromFile(fileName)); t->setSignedData(Input::createFromFile(w->signedDataFileName())); task = t; kleo_assert(fileName == w->inputFileName()); } break; case DecryptVerifyOperationWidget::VerifyDetachedWithSignedData: { std::shared_ptr t(new VerifyDetachedTask); t->setInput(Input::createFromFile(w->inputFileName())); t->setSignedData(Input::createFromFile(fileName)); task = t; kleo_assert(fileName == w->signedDataFileName()); } break; case DecryptVerifyOperationWidget::DecryptVerifyOpaque: { const unsigned int classification = classify(fileName); qCDebug(KLEOPATRA_LOG) << "classified" << fileName << "as" << printableClassification(classification); const std::shared_ptr ad = w->selectedArchiveDefinition(); const Protocol proto = isOpenPGP(classification) ? OpenPGP : isCMS(classification) ? CMS : ad /* _needs_ the info */ ? throw Exception(gpg_error(GPG_ERR_CONFLICT), i18n("Cannot determine whether input data is OpenPGP or CMS")) : /* else we don't care */ UnknownProtocol; const std::shared_ptr input = Input::createFromFile(fileName); const std::shared_ptr output = ad ? ad->createOutputFromUnpackCommand(proto, fileName, outDir) : /*else*/ Output::createFromFile(outDir.absoluteFilePath(outputFileName(QFileInfo(fileName).fileName())), overwritePolicy); if (mayBeCipherText(classification)) { qCDebug(KLEOPATRA_LOG) << "creating a DecryptVerifyTask"; std::shared_ptr t(new DecryptVerifyTask); t->setInput(input); t->setOutput(output); task = t; } else { qCDebug(KLEOPATRA_LOG) << "creating a VerifyOpaqueTask"; std::shared_ptr t(new VerifyOpaqueTask); t->setInput(input); t->setOutput(output); task = t; } kleo_assert(fileName == w->inputFileName()); } break; } task->autodetectProtocolFromInput(); return task; } DecryptVerifyFilesController::Private::Private(DecryptVerifyFilesController *qq) : q(qq), m_errorDetected(false), m_operation(DecryptVerify) { qRegisterMetaType(); } void DecryptVerifyFilesController::Private::slotWizardOperationPrepared() { ensureWizardCreated(); std::vector > tasks = buildTasks(m_filesAfterPreparation, std::shared_ptr(new OverwritePolicy(m_wizard))); if (tasks.empty()) { reportError(makeGnuPGError(GPG_ERR_ASS_NO_INPUT), i18n("No usable inputs found")); } kleo_assert(m_runnableTasks.empty()); m_runnableTasks.swap(tasks); std::shared_ptr coll(new TaskCollection); for (const auto &i: m_runnableTasks) { q->connectTask(i); } coll->setTasks(m_runnableTasks); m_wizard->setTaskCollection(coll); QTimer::singleShot(0, q, SLOT(schedule())); } void DecryptVerifyFilesController::Private::slotWizardCanceled() { q->emitDoneOrError(); } void DecryptVerifyFilesController::doTaskDone(const Task *task, const std::shared_ptr &result) { Q_ASSERT(task); Q_UNUSED(task) // We could just delete the tasks here, but we can't use // Qt::QueuedConnection here (we need sender()) and other slots // might not yet have executed. Therefore, we push completed tasks // into a burial container d->m_completedTasks.push_back(d->m_runningTask); d->m_runningTask.reset(); if (const std::shared_ptr &dvr = std::dynamic_pointer_cast(result)) { d->m_results.push_back(dvr); } QTimer::singleShot(0, this, SLOT(schedule())); } void DecryptVerifyFilesController::Private::schedule() { if (!m_runningTask && !m_runnableTasks.empty()) { const std::shared_ptr t = m_runnableTasks.back(); m_runnableTasks.pop_back(); t->start(); m_runningTask = t; } if (!m_runningTask) { kleo_assert(m_runnableTasks.empty()); for (const auto &i: m_results) { Q_EMIT q->verificationResult(i->verificationResult()); } q->emitDoneOrError(); } } void DecryptVerifyFilesController::Private::ensureWizardCreated() { if (m_wizard) { return; } std::unique_ptr w(new DecryptVerifyFilesWizard); w->setWindowTitle(i18nc("@title:window", "Decrypt/Verify Files")); w->setAttribute(Qt::WA_DeleteOnClose); connect(w.get(), SIGNAL(operationPrepared()), q, SLOT(slotWizardOperationPrepared()), Qt::QueuedConnection); connect(w.get(), SIGNAL(canceled()), q, SLOT(slotWizardCanceled()), Qt::QueuedConnection); m_wizard = w.release(); } namespace { struct FindExtension { const QString ext; const Protocol proto; FindExtension(const QString &ext, Protocol proto) : ext(ext), proto(proto) {} bool operator()(const std::shared_ptr &ad) const { qCDebug(KLEOPATRA_LOG) << " considering" << (ad ? ad->label() : QStringLiteral("")) << "for" << ext; bool result; if (proto == UnknownProtocol) { result = ad && (ad->extensions(OpenPGP).contains(ext, Qt::CaseInsensitive) || ad->extensions(CMS).contains(ext, Qt::CaseInsensitive)); } else { result = ad && ad->extensions(proto).contains(ext, Qt::CaseInsensitive); } qCDebug(KLEOPATRA_LOG) << (result ? " -> matches" : " -> doesn't match"); return result; } }; } std::shared_ptr DecryptVerifyFilesController::pick_archive_definition(GpgME::Protocol proto, const std::vector< std::shared_ptr > &ads, const QString &filename) { const QFileInfo fi(outputFileName(filename)); QString extension = fi.completeSuffix(); if (extension == QLatin1String("out")) { // added by outputFileName() -> useless return std::shared_ptr(); } if (extension.endsWith(QLatin1String(".out"))) { // added by outputFileName() -> remove extension.chop(4); } for (;;) { const auto it = std::find_if(ads.begin(), ads.end(), FindExtension(extension, proto)); if (it != ads.end()) { return *it; } const int idx = extension.indexOf(QLatin1Char('.')); if (idx < 0) { return std::shared_ptr(); } extension = extension.mid(idx + 1); } } void DecryptVerifyFilesController::Private::prepareWizardFromPassedFiles() { ensureWizardCreated(); const std::vector< std::shared_ptr > archiveDefinitions = ArchiveDefinition::getArchiveDefinitions(); unsigned int counter = 0; for (const auto &fname: std::as_const(m_passedFiles)) { kleo_assert(!fname.isEmpty()); const unsigned int classification = classify(fname); const Protocol proto = findProtocol(classification); if (mayBeOpaqueSignature(classification) || mayBeCipherText(classification) || mayBeDetachedSignature(classification)) { DecryptVerifyOperationWidget *const op = m_wizard->operationWidget(counter++); kleo_assert(op != nullptr); op->setArchiveDefinitions(archiveDefinitions); const QString signedDataFileName = findSignedData(fname); // this breaks opaque signatures whose source files still // happen to exist in the same directory. Until we have // content-based classification, this is the most unlikely // case, so that's the case we break. ### FIXME remove when content-classify is done if (mayBeDetachedSignature(classification) && !signedDataFileName.isEmpty()) { op->setMode(DecryptVerifyOperationWidget::VerifyDetachedWithSignature); } // ### end FIXME else if (mayBeOpaqueSignature(classification) || mayBeCipherText(classification)) { op->setMode(DecryptVerifyOperationWidget::DecryptVerifyOpaque, q->pick_archive_definition(proto, archiveDefinitions, fname)); } else { op->setMode(DecryptVerifyOperationWidget::VerifyDetachedWithSignature); } op->setInputFileName(fname); op->setSignedDataFileName(signedDataFileName); m_filesAfterPreparation << fname; } else { // probably the signed data file was selected: const QStringList signatures = findSignatures(fname); if (signatures.empty()) { // We are assuming this is a detached signature file, but // there were no signature files for it. Let's guess it's encrypted after all. // ### FIXME once we have a proper heuristic for this, this should move into // classify() and/or classifyContent() DecryptVerifyOperationWidget *const op = m_wizard->operationWidget(counter++); kleo_assert(op != nullptr); op->setArchiveDefinitions(archiveDefinitions); op->setMode(DecryptVerifyOperationWidget::DecryptVerifyOpaque, q->pick_archive_definition(proto, archiveDefinitions, fname)); op->setInputFileName(fname); m_filesAfterPreparation << fname; } else { for (const auto &s: signatures) { DecryptVerifyOperationWidget *op = m_wizard->operationWidget(counter++); kleo_assert(op != nullptr); op->setArchiveDefinitions(archiveDefinitions); op->setMode(DecryptVerifyOperationWidget::VerifyDetachedWithSignedData); op->setInputFileName(s); op->setSignedDataFileName(fname); m_filesAfterPreparation << fname; } } } } m_wizard->setOutputDirectory(heuristicBaseDirectory(m_passedFiles)); return; } std::vector< std::shared_ptr > DecryptVerifyFilesController::Private::buildTasks(const QStringList &fileNames, const std::shared_ptr &overwritePolicy) { const bool useOutDir = m_wizard->useOutputDirectory(); const QFileInfo outDirInfo(m_wizard->outputDirectory()); kleo_assert(!useOutDir || outDirInfo.isDir()); const QDir outDir(outDirInfo.absoluteFilePath()); kleo_assert(!useOutDir || outDir.exists()); std::vector > tasks; for (int i = 0, end = fileNames.size(); i != end; ++i) try { const QDir fileDir = QFileInfo(fileNames[i]).absoluteDir(); kleo_assert(fileDir.exists()); tasks.push_back(taskFromOperationWidget(m_wizard->operationWidget(static_cast(i)), fileNames[i], useOutDir ? outDir : fileDir, overwritePolicy)); } catch (const GpgME::Exception &e) { - tasks.push_back(Task::makeErrorTask(e.error().code(), QString::fromLocal8Bit(e.what()), fileNames[i])); + tasks.push_back(Task::makeErrorTask(e.error(), QString::fromLocal8Bit(e.what()), fileNames[i])); } return tasks; } void DecryptVerifyFilesController::setFiles(const QStringList &files) { d->m_passedFiles = files; } void DecryptVerifyFilesController::Private::ensureWizardVisible() { ensureWizardCreated(); q->bringToForeground(m_wizard); } DecryptVerifyFilesController::DecryptVerifyFilesController(QObject *parent) : Controller(parent), d(new Private(this)) { } DecryptVerifyFilesController::DecryptVerifyFilesController(const std::shared_ptr &ctx, QObject *parent) : Controller(ctx, parent), d(new Private(this)) { } DecryptVerifyFilesController::~DecryptVerifyFilesController() { qCDebug(KLEOPATRA_LOG); } void DecryptVerifyFilesController::start() { d->prepareWizardFromPassedFiles(); d->ensureWizardVisible(); } void DecryptVerifyFilesController::setOperation(DecryptVerifyOperation op) { d->m_operation = op; } DecryptVerifyOperation DecryptVerifyFilesController::operation() const { return d->m_operation; } void DecryptVerifyFilesController::Private::cancelAllTasks() { // we just kill all runnable tasks - this will not result in // signal emissions. m_runnableTasks.clear(); // a cancel() will result in a call to if (m_runningTask) { m_runningTask->cancel(); } } void DecryptVerifyFilesController::cancel() { qCDebug(KLEOPATRA_LOG); try { d->m_errorDetected = true; if (d->m_wizard) { d->m_wizard->close(); } d->cancelAllTasks(); } catch (const std::exception &e) { qCDebug(KLEOPATRA_LOG) << "Caught exception: " << e.what(); } } #include "moc_decryptverifyfilescontroller.cpp" diff --git a/src/crypto/decryptverifytask.cpp b/src/crypto/decryptverifytask.cpp index a1ed97fe6..98c7abbe8 100644 --- a/src/crypto/decryptverifytask.cpp +++ b/src/crypto/decryptverifytask.cpp @@ -1,1617 +1,1617 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifytask.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #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 #include // Qt::escape #include #include using namespace Kleo::Crypto; using namespace Kleo; using namespace GpgME; using namespace KMime::Types; namespace { 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; const auto userIDs{key.userIDs()}; for (const UserID &id : 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(quint32(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 (DeVSCompliance::isCompliant()) { text += (QStringLiteral("
") + (sig.isDeVs() ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "The signature is %1", DeVSCompliance::name(true)) : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "The signature is not %1.", DeVSCompliance::name(true)))); } 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) { const auto userIDs{key.userIDs()}; for (const UserID &id : 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."); } else if (result.isLegacyCipherNoMDC()) { return i18n("Decryption failed: %1.", i18n("No integrity protection (MDC).")); } 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 formatRecipientsDetails(const std::vector &knownRecipients, unsigned int numRecipients) { if (numRecipients == 0) { return {}; } if (knownRecipients.empty()) { return QLatin1String("") + i18np("One unknown recipient.", "%1 unknown recipients.", numRecipients) + QLatin1String(""); } QString details = i18np("Recipient:", "Recipients:", numRecipients); if (numRecipients == 1) { details += QLatin1Char(' ') + renderKey(knownRecipients.front()); } else { details += QLatin1String("
    "); for (const Key &key : knownRecipients) { details += QLatin1String("
  • ") + renderKey(key) + QLatin1String("
  • "); } if (knownRecipients.size() < numRecipients) { details += QLatin1String("
  • ") + i18np("One unknown recipient", "%1 unknown recipients", numRecipients - knownRecipients.size()) + QLatin1String("
  • "); } details += QLatin1String("
"); } return details; } static QString formatDecryptionResultDetails(const DecryptionResult &res, const std::vector &recipients, const QString &errorString, bool isSigned, const QPointer &task) { if ((res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty()) { return i18n("Input error: %1", errorString); } if (res.isNull() || res.error() || res.error().isCanceled()) { return formatRecipientsDetails(recipients, res.numRecipients()); } QString details; if (DeVSCompliance::isCompliant()) { details += ((res.isDeVs() ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "The decryption is %1.", DeVSCompliance::name(true)) : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "The decryption is not %1.", DeVSCompliance::name(true))) + 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 (!isSigned) { details += i18n("Note: You cannot be sure who encrypted this message as it is not signed.") + QLatin1String("
"); } 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("

"); } details += formatRecipientsDetails(recipients, res.numRecipients()); 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, const QString &fileName, - int errCode, + const GpgME::Error &error, 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_fileName(fileName), - m_error(errCode), + m_error(error), 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; QString m_fileName; - int m_error; + GpgME::Error 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(), + err, what, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } std::shared_ptr AbstractDecryptVerifyTask::fromDecryptVerifyResult(const DecryptionResult &dr, const VerificationResult &vr, const QByteArray &plaintext, const QString &fileName, const AuditLog &auditLog) { - int err = dr.error() ? dr.error().code() : vr.error().code(); + const auto err = dr.error() ? dr.error() : vr.error(); return std::shared_ptr(new DecryptVerifyResult( DecryptVerify, vr, dr, plaintext, fileName, 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(), + err, 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(), + err, 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(), + err, details, inputLabel(), outputLabel(), auditLog, this, informativeSender())); } DecryptVerifyResult::DecryptVerifyResult(DecryptVerifyOperation type, const VerificationResult &vr, const DecryptionResult &dr, const QByteArray &stuff, const QString &fileName, - int errCode, + const GpgME::Error &error, 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, fileName, errCode, errString, inputLabel, outputLabel, auditLog, parentTask, informativeSender, this)) + : Task::Result(), d(new Private(type, vr, dr, stuff, fileName, error, 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); } -int DecryptVerifyResult::errorCode() const +GpgME::Error DecryptVerifyResult::error() 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; } QString DecryptVerifyResult::fileName() const { return d->m_fileName; } 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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(Error::fromCode(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, m_output->fileName(), 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(); 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(); } } } 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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromDecryptVerifyResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromDecryptResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); return; } catch (...) { emitResult(q->fromDecryptResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromVerifyOpaqueResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog)); } catch (...) { emitResult(q->fromVerifyDetachedResult(Error::fromCode(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(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog())); } catch (...) { d->emitResult(fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog())); } } #include "moc_decryptverifytask.cpp" diff --git a/src/crypto/decryptverifytask.h b/src/crypto/decryptverifytask.h index 690efa40b..ec2302ba5 100644 --- a/src/crypto/decryptverifytask.h +++ b/src/crypto/decryptverifytask.h @@ -1,260 +1,260 @@ /* -*- mode: c++; c-basic-offset:4 -*- decryptverifytask.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "task.h" #include #include #include namespace KMime { namespace Types { class Mailbox; } } namespace GpgME { class DecryptionResult; class VerificationResult; class Key; class Signature; } namespace Kleo { class Input; class Output; class AuditLog; } namespace Kleo { namespace Crypto { class DecryptVerifyResult; class AbstractDecryptVerifyTask : public Task { Q_OBJECT public: explicit AbstractDecryptVerifyTask(QObject *parent = nullptr); ~AbstractDecryptVerifyTask() override; virtual void autodetectProtocolFromInput() = 0; KMime::Types::Mailbox informativeSender() const; void setInformativeSender(const KMime::Types::Mailbox &senders); virtual QString inputLabel() const = 0; virtual QString outputLabel() const = 0; Q_SIGNALS: void decryptVerifyResult(const std::shared_ptr &); protected: std::shared_ptr fromDecryptResult(const GpgME::DecryptionResult &dr, const QByteArray &plaintext, const AuditLog &auditLog); std::shared_ptr fromDecryptResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog); std::shared_ptr fromDecryptVerifyResult(const GpgME::DecryptionResult &dr, const GpgME::VerificationResult &vr, const QByteArray &plaintext, const QString &fileName, const AuditLog &auditLog); std::shared_ptr fromDecryptVerifyResult(const GpgME::Error &err, const QString &what, const AuditLog &auditLog); std::shared_ptr fromVerifyOpaqueResult(const GpgME::VerificationResult &vr, const QByteArray &plaintext, const AuditLog &auditLog); std::shared_ptr fromVerifyOpaqueResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog); std::shared_ptr fromVerifyDetachedResult(const GpgME::VerificationResult &vr, const AuditLog &auditLog); std::shared_ptr fromVerifyDetachedResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog); private: class Private; kdtools::pimpl_ptr d; }; class DecryptTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit DecryptTask(QObject *parent = nullptr); ~DecryptTask() override; void setInput(const std::shared_ptr &input); void setOutput(const std::shared_ptr &output); void setProtocol(GpgME::Protocol prot); void autodetectProtocolFromInput() override; QString label() const override; GpgME::Protocol protocol() const override; QString inputLabel() const override; QString outputLabel() const override; public Q_SLOTS: void cancel() override; private: void doStart() override; unsigned long long inputSize() const override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotResult(GpgME::DecryptionResult, QByteArray)) }; class VerifyDetachedTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit VerifyDetachedTask(QObject *parent = nullptr); ~VerifyDetachedTask() override; void setInput(const std::shared_ptr &input); void setSignedData(const std::shared_ptr &signedData); void setProtocol(GpgME::Protocol prot); void autodetectProtocolFromInput() override; QString label() const override; GpgME::Protocol protocol() const override; QString inputLabel() const override; QString outputLabel() const override; public Q_SLOTS: void cancel() override; private: void doStart() override; unsigned long long inputSize() const override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotResult(GpgME::VerificationResult)) }; class VerifyOpaqueTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit VerifyOpaqueTask(QObject *parent = nullptr); ~VerifyOpaqueTask() override; void setInput(const std::shared_ptr &input); void setOutput(const std::shared_ptr &output); void setProtocol(GpgME::Protocol prot); void autodetectProtocolFromInput()override; QString label() const override; GpgME::Protocol protocol() const override; QString inputLabel() const override; QString outputLabel() const override; public Q_SLOTS: void cancel() override; private: void doStart() override; unsigned long long inputSize() const override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotResult(GpgME::VerificationResult, QByteArray)) }; class DecryptVerifyTask : public AbstractDecryptVerifyTask { Q_OBJECT public: explicit DecryptVerifyTask(QObject *parent = nullptr); ~DecryptVerifyTask() override; void setInput(const std::shared_ptr &input); void setSignedData(const std::shared_ptr &signedData); void setOutput(const std::shared_ptr &output); void setProtocol(GpgME::Protocol prot); void autodetectProtocolFromInput() override; QString label() const override; GpgME::Protocol protocol() const override; void setIgnoreMDCError(bool value); QString inputLabel() const override; QString outputLabel() const override; public Q_SLOTS: void cancel() override; private: void doStart() override; unsigned long long inputSize() const override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotResult(GpgME::DecryptionResult, GpgME::VerificationResult, QByteArray)) }; class DecryptVerifyResult : public Task::Result { friend class ::Kleo::Crypto::AbstractDecryptVerifyTask; public: class SenderInfo; QString overview() const override; QString details() const override; - int errorCode() const override; + GpgME::Error error() const override; QString errorString() const override; VisualCode code() const override; AuditLog auditLog() const override; QPointer parentTask() const override; GpgME::VerificationResult verificationResult() const; GpgME::DecryptionResult decryptionResult() const; QString fileName() const; private: static QString keyToString(const GpgME::Key &key); private: DecryptVerifyResult(); DecryptVerifyResult(const DecryptVerifyResult &); DecryptVerifyResult &operator=(const DecryptVerifyResult &other); DecryptVerifyResult(DecryptVerifyOperation op, const GpgME::VerificationResult &vr, const GpgME::DecryptionResult &dr, const QByteArray &stuff, const QString &fileName, - int errCode, + const GpgME::Error &error, const QString &errString, const QString &inputLabel, const QString &outputLabel, const AuditLog &auditLog, Task *parentTask, const KMime::Types::Mailbox &informativeSender); private: class Private; kdtools::pimpl_ptr d; }; } } diff --git a/src/crypto/encryptemailtask.cpp b/src/crypto/encryptemailtask.cpp index 65c96364d..742779a89 100644 --- a/src/crypto/encryptemailtask.cpp +++ b/src/crypto/encryptemailtask.cpp @@ -1,232 +1,232 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/encryptemailtask.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "encryptemailtask.h" #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape using namespace Kleo; using namespace Kleo::Crypto; using namespace GpgME; namespace { class EncryptEMailResult : public Task::Result { const EncryptionResult m_result; const AuditLog m_auditLog; public: EncryptEMailResult(const EncryptionResult &r, const AuditLog &auditLog) : Task::Result(), m_result(r), m_auditLog(auditLog) {} QString overview() const override; QString details() const override; - int errorCode() const override; + GpgME::Error error() const override; QString errorString() const override; VisualCode code() const override; AuditLog auditLog() const override; }; QString makeResultString(const EncryptionResult &res) { const Error err = res.error(); if (err.isCanceled()) { return i18n("Encryption canceled."); } if (err) { return i18n("Encryption failed: %1", QString::fromLocal8Bit(err.asString()).toHtmlEscaped()); } return i18n("Encryption succeeded."); } } class EncryptEMailTask::Private { friend class ::Kleo::Crypto::EncryptEMailTask; EncryptEMailTask *const q; public: explicit Private(EncryptEMailTask *qq); private: std::unique_ptr createJob(GpgME::Protocol proto); private: void slotResult(const EncryptionResult &); private: std::shared_ptr input; std::shared_ptr output; std::vector recipients; QPointer job; }; EncryptEMailTask::Private::Private(EncryptEMailTask *qq) : q(qq), input(), output(), job(nullptr) { } EncryptEMailTask::EncryptEMailTask(QObject *p) : Task(p), d(new Private(this)) { } EncryptEMailTask::~EncryptEMailTask() {} void EncryptEMailTask::setInput(const std::shared_ptr &input) { kleo_assert(!d->job); kleo_assert(input); d->input = input; } void EncryptEMailTask::setOutput(const std::shared_ptr &output) { kleo_assert(!d->job); kleo_assert(output); d->output = output; } void EncryptEMailTask::setRecipients(const std::vector &recipients) { kleo_assert(!d->job); kleo_assert(!recipients.empty()); d->recipients = recipients; } Protocol EncryptEMailTask::protocol() const { kleo_assert(!d->recipients.empty()); return d->recipients.front().protocol(); } QString EncryptEMailTask::label() const { return d->input ? d->input->label() : QString(); } unsigned long long EncryptEMailTask::inputSize() const { return d->input ? d->input->size() : 0; } void EncryptEMailTask::doStart() { kleo_assert(!d->job); kleo_assert(d->input); kleo_assert(d->output); kleo_assert(!d->recipients.empty()); std::unique_ptr job = d->createJob(protocol()); kleo_assert(job.get()); job->start(d->recipients, d->input->ioDevice(), d->output->ioDevice(), /*alwaysTrust=*/true); d->job = job.release(); } void EncryptEMailTask::cancel() { if (d->job) { d->job->slotCancel(); } } std::unique_ptr EncryptEMailTask::Private::createJob(GpgME::Protocol proto) { const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(backend); bool shouldArmor = (proto == OpenPGP || q->asciiArmor()) && !output->binaryOpt(); std::unique_ptr encryptJob(backend->encryptJob(shouldArmor, /*textmode=*/false)); kleo_assert(encryptJob.get()); if (proto == CMS && !q->asciiArmor() && !output->binaryOpt()) { encryptJob->setOutputIsBase64Encoded(true); } connect(encryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); connect(encryptJob.get(), SIGNAL(result(GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::EncryptionResult))); return encryptJob; } void EncryptEMailTask::Private::slotResult(const EncryptionResult &result) { const auto *const job = qobject_cast(q->sender()); if (result.error().code()) { output->cancel(); } else { output->finalize(); } q->emitResult(std::shared_ptr(new EncryptEMailResult(result, AuditLog::fromJob(job)))); } QString EncryptEMailResult::overview() const { return makeOverview(makeResultString(m_result)); } QString EncryptEMailResult::details() const { return QString(); } -int EncryptEMailResult::errorCode() const +GpgME::Error EncryptEMailResult::error() const { - return m_result.error().encodedError(); + return m_result.error(); } QString EncryptEMailResult::errorString() const { return hasError() ? makeResultString(m_result) : QString(); } AuditLog EncryptEMailResult::auditLog() const { return m_auditLog; } Task::Result::VisualCode EncryptEMailResult::code() const { if (m_result.error().isCanceled()) { return Warning; } return m_result.error().code() ? NeutralError : NeutralSuccess; } #include "moc_encryptemailtask.cpp" diff --git a/src/crypto/signemailtask.cpp b/src/crypto/signemailtask.cpp index c6cbcae3d..05e732b7f 100644 --- a/src/crypto/signemailtask.cpp +++ b/src/crypto/signemailtask.cpp @@ -1,284 +1,284 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signemailtask.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "signemailtask.h" #include #include #include #include #include #include #include #include #include #include #include #include // for Qt::escape #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace GpgME; namespace { class SignEMailResult : public Task::Result { const SigningResult m_result; const AuditLog m_auditLog; public: explicit SignEMailResult(const SigningResult &r, const AuditLog &auditLog) : Task::Result(), m_result(r), m_auditLog(auditLog) {} QString overview() const override; QString details() const override; - int errorCode() const override; + GpgME::Error error() const override; QString errorString() const override; VisualCode code() const override; AuditLog auditLog() const override; }; QString makeResultString(const SigningResult &res) { const Error err = res.error(); if (err.isCanceled()) { return i18n("Signing canceled."); } if (err) { return i18n("Signing failed: %1", QString::fromLocal8Bit(err.asString()).toHtmlEscaped()); } return i18n("Signing succeeded."); } } class SignEMailTask::Private { friend class ::Kleo::Crypto::SignEMailTask; SignEMailTask *const q; public: explicit Private(SignEMailTask *qq); private: std::unique_ptr createJob(GpgME::Protocol proto); private: void slotResult(const SigningResult &); private: std::shared_ptr input; std::shared_ptr output; std::vector signers; bool detached; bool clearsign; QString micAlg; QPointer job; }; SignEMailTask::Private::Private(SignEMailTask *qq) : q(qq), input(), output(), signers(), detached(false), clearsign(false), micAlg(), job(nullptr) { } SignEMailTask::SignEMailTask(QObject *p) : Task(p), d(new Private(this)) { } SignEMailTask::~SignEMailTask() {} void SignEMailTask::setInput(const std::shared_ptr &input) { kleo_assert(!d->job); kleo_assert(input); d->input = input; } void SignEMailTask::setOutput(const std::shared_ptr &output) { kleo_assert(!d->job); kleo_assert(output); d->output = output; } void SignEMailTask::setSigners(const std::vector &signers) { kleo_assert(!d->job); kleo_assert(!signers.empty()); kleo_assert(std::none_of(signers.cbegin(), signers.cend(), std::mem_fn(&Key::isNull))); d->signers = signers; } void SignEMailTask::setDetachedSignature(bool detached) { kleo_assert(!d->job); d->detached = detached; d->clearsign = false; } void SignEMailTask::setClearsign(bool clear) { kleo_assert(!d->job); d->clearsign = clear; d->detached = false; } Protocol SignEMailTask::protocol() const { kleo_assert(!d->signers.empty()); return d->signers.front().protocol(); } QString SignEMailTask::label() const { return d->input ? d->input->label() : QString(); } unsigned long long SignEMailTask::inputSize() const { return d->input ? d->input->size() : 0; } void SignEMailTask::doStart() { kleo_assert(!d->job); kleo_assert(d->input); kleo_assert(d->output); kleo_assert(!d->signers.empty()); d->micAlg.clear(); std::unique_ptr job = d->createJob(protocol()); kleo_assert(job.get()); job->start(d->signers, d->input->ioDevice(), d->output->ioDevice(), d->clearsign ? GpgME::Clearsigned : d->detached ? GpgME::Detached : GpgME::NormalSignatureMode); d->job = job.release(); } void SignEMailTask::cancel() { if (d->job) { d->job->slotCancel(); } } std::unique_ptr SignEMailTask::Private::createJob(GpgME::Protocol proto) { const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(backend); bool shouldArmor = (proto == OpenPGP || q->asciiArmor()) && !output->binaryOpt(); std::unique_ptr signJob(backend->signJob(/*armor=*/ shouldArmor, /*textmode=*/false)); kleo_assert(signJob.get()); if (proto == CMS && !q->asciiArmor() && !output->binaryOpt()) { signJob->setOutputIsBase64Encoded(true); } connect(signJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); connect(signJob.get(), SIGNAL(result(GpgME::SigningResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult))); return signJob; } static QString collect_micalgs(const GpgME::SigningResult &result, GpgME::Protocol proto) { const std::vector css = result.createdSignatures(); QStringList micalgs; std::transform(css.begin(), css.end(), std::back_inserter(micalgs), [](const GpgME::CreatedSignature &sig) { return QString::fromLatin1(sig.hashAlgorithmAsString()).toLower(); }); if (proto == GpgME::OpenPGP) for (QStringList::iterator it = micalgs.begin(), end = micalgs.end(); it != end; ++it) { it->prepend(QLatin1String("pgp-")); } micalgs.sort(); micalgs.erase(std::unique(micalgs.begin(), micalgs.end()), micalgs.end()); return micalgs.join(QLatin1Char(',')); } void SignEMailTask::Private::slotResult(const SigningResult &result) { const auto *const job = qobject_cast(q->sender()); if (result.error().code()) { output->cancel(); } else { output->finalize(); micAlg = collect_micalgs(result, q->protocol()); } q->emitResult(std::shared_ptr(new SignEMailResult(result, AuditLog::fromJob(job)))); } QString SignEMailTask::micAlg() const { return d->micAlg; } QString SignEMailResult::overview() const { return makeOverview(makeResultString(m_result)); } QString SignEMailResult::details() const { return QString(); } -int SignEMailResult::errorCode() const +GpgME::Error SignEMailResult::error() const { - return m_result.error().encodedError(); + return m_result.error(); } QString SignEMailResult::errorString() const { return hasError() ? makeResultString(m_result) : QString(); } Task::Result::VisualCode SignEMailResult::code() const { if (m_result.error().isCanceled()) { return Warning; } return m_result.error().code() ? NeutralError : NeutralSuccess; } AuditLog SignEMailResult::auditLog() const { return m_auditLog; } #include "moc_signemailtask.cpp" diff --git a/src/crypto/signencrypttask.cpp b/src/crypto/signencrypttask.cpp index 813bbca7f..f43e7e2d6 100644 --- a/src/crypto/signencrypttask.cpp +++ b/src/crypto/signencrypttask.cpp @@ -1,692 +1,692 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/signencrypttask.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "signencrypttask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include // for Qt::escape using namespace Kleo; using namespace Kleo::Crypto; using namespace GpgME; namespace { QString formatInputOutputLabel(const QString &input, const QString &output, bool outputDeleted) { return i18nc("Input file --> Output file (rarr is arrow", "%1 → %2", input.toHtmlEscaped(), outputDeleted ? QStringLiteral("%1").arg(output.toHtmlEscaped()) : output.toHtmlEscaped()); } class ErrorResult : public Task::Result { public: ErrorResult(bool sign, bool encrypt, const Error &err, const QString &errStr, const QString &input, const QString &output, const AuditLog &auditLog) : Task::Result(), m_sign(sign), m_encrypt(encrypt), m_error(err), m_errString(errStr), m_inputLabel(input), m_outputLabel(output), m_auditLog(auditLog) {} QString overview() const override; QString details() const override; - int errorCode() const override + GpgME::Error error() const override { - return m_error.encodedError(); + return m_error; } QString errorString() const override { return m_errString; } VisualCode code() const override { return NeutralError; } AuditLog auditLog() const override { return m_auditLog; } private: const bool m_sign; const bool m_encrypt; const Error m_error; const QString m_errString; const QString m_inputLabel; const QString m_outputLabel; const AuditLog m_auditLog; }; class SignEncryptFilesResult : public Task::Result { public: SignEncryptFilesResult(const SigningResult &sr, const std::shared_ptr &input, const std::shared_ptr &output, bool outputCreated, const AuditLog &auditLog) : Task::Result(), m_sresult(sr), m_inputLabel(input ? input->label() : QString()), m_inputErrorString(input ? input->errorString() : QString()), m_outputLabel(output ? output->label() : QString()), m_outputErrorString(output ? output->errorString() : QString()), m_outputCreated(outputCreated), m_auditLog(auditLog) { qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString << "\noutputError:" << m_outputErrorString; Q_ASSERT(!m_sresult.isNull()); } SignEncryptFilesResult(const EncryptionResult &er, const std::shared_ptr &input, const std::shared_ptr &output, bool outputCreated, const AuditLog &auditLog) : Task::Result(), m_eresult(er), m_inputLabel(input ? input->label() : QString()), m_inputErrorString(input ? input->errorString() : QString()), m_outputLabel(output ? output->label() : QString()), m_outputErrorString(output ? output->errorString() : QString()), m_outputCreated(outputCreated), m_auditLog(auditLog) { qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString << "\noutputError:" << m_outputErrorString; Q_ASSERT(!m_eresult.isNull()); } SignEncryptFilesResult(const SigningResult &sr, const EncryptionResult &er, const std::shared_ptr &input, const std::shared_ptr &output, bool outputCreated, const AuditLog &auditLog) : Task::Result(), m_sresult(sr), m_eresult(er), m_inputLabel(input ? input->label() : QString()), m_inputErrorString(input ? input->errorString() : QString()), m_outputLabel(output ? output->label() : QString()), m_outputErrorString(output ? output->errorString() : QString()), m_outputCreated(outputCreated), m_auditLog(auditLog) { qCDebug(KLEOPATRA_LOG) << "\ninputError :" << m_inputErrorString << "\noutputError:" << m_outputErrorString; Q_ASSERT(!m_sresult.isNull() || !m_eresult.isNull()); } QString overview() const override; QString details() const override; - int errorCode() const override; + GpgME::Error error() const override; QString errorString() const override; VisualCode code() const override; AuditLog auditLog() const override; private: const SigningResult m_sresult; const EncryptionResult m_eresult; const QString m_inputLabel; const QString m_inputErrorString; const QString m_outputLabel; const QString m_outputErrorString; const bool m_outputCreated; const AuditLog m_auditLog; }; static QString makeSigningOverview(const Error &err) { if (err.isCanceled()) { return i18n("Signing canceled."); } if (err) { return i18n("Signing failed."); } return i18n("Signing succeeded."); } static QString makeResultOverview(const SigningResult &result) { return makeSigningOverview(result.error()); } static QString makeEncryptionOverview(const Error &err) { if (err.isCanceled()) { return i18n("Encryption canceled."); } if (err) { return i18n("Encryption failed."); } return i18n("Encryption succeeded."); } static QString makeResultOverview(const EncryptionResult &result) { return makeEncryptionOverview(result.error()); } static QString makeResultOverview(const SigningResult &sr, const EncryptionResult &er) { if (er.isNull() && sr.isNull()) { return QString(); } if (er.isNull()) { return makeResultOverview(sr); } if (sr.isNull()) { return makeResultOverview(er); } if (sr.error().isCanceled() || sr.error()) { return makeResultOverview(sr); } if (er.error().isCanceled() || er.error()) { return makeResultOverview(er); } return i18n("Signing and encryption succeeded."); } static QString escape(QString s) { s = s.toHtmlEscaped(); s.replace(QLatin1Char('\n'), QStringLiteral("
")); return s; } static QString makeResultDetails(const SigningResult &result, const QString &inputError, const QString &outputError) { const Error err = result.error(); if (err.code() == GPG_ERR_EIO) { if (!inputError.isEmpty()) { return i18n("Input error: %1", escape(inputError)); } else if (!outputError.isEmpty()) { return i18n("Output error: %1", escape(outputError)); } } if (err || err.isCanceled()) { return QString::fromLocal8Bit(err.asString()).toHtmlEscaped(); } return QString(); } static QString makeResultDetails(const EncryptionResult &result, const QString &inputError, const QString &outputError) { const Error err = result.error(); if (err.code() == GPG_ERR_EIO) { if (!inputError.isEmpty()) { return i18n("Input error: %1", escape(inputError)); } else if (!outputError.isEmpty()) { return i18n("Output error: %1", escape(outputError)); } } if (err || err.isCanceled()) { return QString::fromLocal8Bit(err.asString()).toHtmlEscaped(); } return i18n(" Encryption succeeded."); } } QString ErrorResult::overview() const { Q_ASSERT(m_error || m_error.isCanceled()); Q_ASSERT(m_sign || m_encrypt); const QString label = formatInputOutputLabel(m_inputLabel, m_outputLabel, true); const bool canceled = m_error.isCanceled(); if (m_sign && m_encrypt) { return canceled ? i18n("%1: Sign/encrypt canceled.", label) : i18n(" %1: Sign/encrypt failed.", label); } return i18nc("label: result. Example: foo -> foo.gpg: Encryption failed.", "%1: %2", label, m_sign ? makeSigningOverview(m_error) : makeEncryptionOverview(m_error)); } QString ErrorResult::details() const { return m_errString; } class SignEncryptTask::Private { friend class ::Kleo::Crypto::SignEncryptTask; SignEncryptTask *const q; public: explicit Private(SignEncryptTask *qq); private: std::unique_ptr createSignJob(GpgME::Protocol proto); std::unique_ptr createSignEncryptJob(GpgME::Protocol proto); std::unique_ptr createEncryptJob(GpgME::Protocol proto); std::shared_ptr makeErrorResult(const Error &err, const QString &errStr, const AuditLog &auditLog); private: void slotResult(const SigningResult &); void slotResult(const SigningResult &, const EncryptionResult &); void slotResult(const EncryptionResult &); private: std::shared_ptr input; std::shared_ptr output; QStringList inputFileNames; QString outputFileName; std::vector signers; std::vector recipients; bool sign : 1; bool encrypt : 1; bool detached : 1; bool symmetric: 1; bool clearsign: 1; QPointer job; std::shared_ptr m_overwritePolicy; }; SignEncryptTask::Private::Private(SignEncryptTask *qq) : q(qq), input(), output(), inputFileNames(), outputFileName(), signers(), recipients(), sign(true), encrypt(true), detached(false), clearsign(false), job(nullptr), m_overwritePolicy(new OverwritePolicy(nullptr)) { q->setAsciiArmor(true); } std::shared_ptr SignEncryptTask::Private::makeErrorResult(const Error &err, const QString &errStr, const AuditLog &auditLog) { return std::shared_ptr(new ErrorResult(sign, encrypt, err, errStr, input->label(), output->label(), auditLog)); } SignEncryptTask::SignEncryptTask(QObject *p) : Task(p), d(new Private(this)) { } SignEncryptTask::~SignEncryptTask() {} void SignEncryptTask::setInputFileName(const QString &fileName) { kleo_assert(!d->job); kleo_assert(!fileName.isEmpty()); d->inputFileNames = QStringList(fileName); } void SignEncryptTask::setInputFileNames(const QStringList &fileNames) { kleo_assert(!d->job); kleo_assert(!fileNames.empty()); d->inputFileNames = fileNames; } void SignEncryptTask::setInput(const std::shared_ptr &input) { kleo_assert(!d->job); kleo_assert(input); d->input = input; } void SignEncryptTask::setOutput(const std::shared_ptr &output) { kleo_assert(!d->job); kleo_assert(output); d->output = output; } void SignEncryptTask::setOutputFileName(const QString &fileName) { kleo_assert(!d->job); kleo_assert(!fileName.isEmpty()); d->outputFileName = fileName; } void SignEncryptTask::setSigners(const std::vector &signers) { kleo_assert(!d->job); d->signers = signers; } void SignEncryptTask::setRecipients(const std::vector &recipients) { kleo_assert(!d->job); d->recipients = recipients; } void SignEncryptTask::setOverwritePolicy(const std::shared_ptr &policy) { kleo_assert(!d->job); d->m_overwritePolicy = policy; } void SignEncryptTask::setSign(bool sign) { kleo_assert(!d->job); d->sign = sign; } void SignEncryptTask::setEncrypt(bool encrypt) { kleo_assert(!d->job); d->encrypt = encrypt; } void SignEncryptTask::setDetachedSignature(bool detached) { kleo_assert(!d->job); d->detached = detached; } void SignEncryptTask::setEncryptSymmetric(bool symmetric) { kleo_assert(!d->job); d->symmetric = symmetric; } void SignEncryptTask::setClearsign(bool clearsign) { kleo_assert(!d->job); d->clearsign = clearsign; } Protocol SignEncryptTask::protocol() const { if (d->sign && !d->signers.empty()) { return d->signers.front().protocol(); } if (d->encrypt || d->symmetric) { if (!d->recipients.empty()) { return d->recipients.front().protocol(); } else { return GpgME::OpenPGP; // symmetric OpenPGP encryption } } throw Kleo::Exception(gpg_error(GPG_ERR_INTERNAL), i18n("Cannot determine protocol for task")); } QString SignEncryptTask::label() const { return d->input ? d->input->label() : QString(); } QString SignEncryptTask::tag() const { return Formatting::displayName(protocol()); } unsigned long long SignEncryptTask::inputSize() const { return d->input ? d->input->size() : 0U; } void SignEncryptTask::doStart() { kleo_assert(!d->job); if (d->sign) { kleo_assert(!d->signers.empty()); } kleo_assert(d->input); if (!d->output) { d->output = Output::createFromFile(d->outputFileName, d->m_overwritePolicy); } if (d->encrypt || d->symmetric) { Context::EncryptionFlags flags = Context::AlwaysTrust; if (d->symmetric) { flags = static_cast(flags | Context::Symmetric); qCDebug(KLEOPATRA_LOG) << "Adding symmetric flag"; } if (d->sign) { std::unique_ptr job = d->createSignEncryptJob(protocol()); kleo_assert(job.get()); #ifdef QGPGME_SUPPORTS_SET_FILENAME if (d->inputFileNames.size() == 1) { job->setFileName(d->inputFileNames.front()); } #endif job->start(d->signers, d->recipients, d->input->ioDevice(), d->output->ioDevice(), flags); d->job = job.release(); } else { std::unique_ptr job = d->createEncryptJob(protocol()); kleo_assert(job.get()); #ifdef QGPGME_SUPPORTS_SET_FILENAME if (d->inputFileNames.size() == 1) { job->setFileName(d->inputFileNames.front()); } #endif job->start(d->recipients, d->input->ioDevice(), d->output->ioDevice(), flags); d->job = job.release(); } } else if (d->sign) { std::unique_ptr job = d->createSignJob(protocol()); kleo_assert(job.get()); kleo_assert(! (d->detached && d->clearsign)); job->start(d->signers, d->input->ioDevice(), d->output->ioDevice(), d->detached ? GpgME::Detached : d->clearsign ? GpgME::Clearsigned : GpgME::NormalSignatureMode); d->job = job.release(); } else { kleo_assert(!"Either 'sign' or 'encrypt' or 'symmetric' must be set!"); } } void SignEncryptTask::cancel() { if (d->job) { d->job->slotCancel(); } } std::unique_ptr SignEncryptTask::Private::createSignJob(GpgME::Protocol proto) { const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(backend); std::unique_ptr signJob(backend->signJob(q->asciiArmor(), /*textmode=*/false)); kleo_assert(signJob.get()); connect(signJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); connect(signJob.get(), SIGNAL(result(GpgME::SigningResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult))); return signJob; } std::unique_ptr SignEncryptTask::Private::createSignEncryptJob(GpgME::Protocol proto) { const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(backend); std::unique_ptr signEncryptJob(backend->signEncryptJob(q->asciiArmor(), /*textmode=*/false)); kleo_assert(signEncryptJob.get()); connect(signEncryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); connect(signEncryptJob.get(), SIGNAL(result(GpgME::SigningResult,GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::SigningResult,GpgME::EncryptionResult))); return signEncryptJob; } std::unique_ptr SignEncryptTask::Private::createEncryptJob(GpgME::Protocol proto) { const QGpgME::Protocol *const backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); kleo_assert(backend); std::unique_ptr encryptJob(backend->encryptJob(q->asciiArmor(), /*textmode=*/false)); kleo_assert(encryptJob.get()); connect(encryptJob.get(), SIGNAL(progress(QString,int,int)), q, SLOT(setProgress(QString,int,int))); connect(encryptJob.get(), SIGNAL(result(GpgME::EncryptionResult,QByteArray)), q, SLOT(slotResult(GpgME::EncryptionResult))); return encryptJob; } void SignEncryptTask::Private::slotResult(const SigningResult &result) { const auto *const job = qobject_cast(q->sender()); const AuditLog auditLog = AuditLog::fromJob(job); bool outputCreated = false; if (input->failed()) { q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO), i18n("Input error: %1", escape( input->errorString())), auditLog)); return; } else if (result.error().code()) { output->cancel(); } else { try { kleo_assert(!result.isNull()); output->finalize(); outputCreated = true; input->finalize(); } catch (const GpgME::Exception &e) { q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } } q->emitResult(std::shared_ptr(new SignEncryptFilesResult(result, input, output, outputCreated, auditLog))); } void SignEncryptTask::Private::slotResult(const SigningResult &sresult, const EncryptionResult &eresult) { const auto *const job = qobject_cast(q->sender()); const AuditLog auditLog = AuditLog::fromJob(job); bool outputCreated = false; if (input->failed()) { output->cancel(); q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO), i18n("Input error: %1", escape( input->errorString())), auditLog)); return; } else if (sresult.error().code() || eresult.error().code()) { output->cancel(); } else { try { kleo_assert(!sresult.isNull() || !eresult.isNull()); output->finalize(); outputCreated = true; input->finalize(); } catch (const GpgME::Exception &e) { q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } } q->emitResult(std::shared_ptr(new SignEncryptFilesResult(sresult, eresult, input, output, outputCreated, auditLog))); } void SignEncryptTask::Private::slotResult(const EncryptionResult &result) { const auto *const job = qobject_cast(q->sender()); const AuditLog auditLog = AuditLog::fromJob(job); bool outputCreated = false; if (input->failed()) { output->cancel(); q->emitResult(makeErrorResult(Error::fromCode(GPG_ERR_EIO), i18n("Input error: %1", escape(input->errorString())), auditLog)); return; } else if (result.error().code()) { output->cancel(); } else { try { kleo_assert(!result.isNull()); output->finalize(); outputCreated = true; input->finalize(); } catch (const GpgME::Exception &e) { q->emitResult(makeErrorResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog)); return; } } q->emitResult(std::shared_ptr(new SignEncryptFilesResult(result, input, output, outputCreated, auditLog))); } QString SignEncryptFilesResult::overview() const { const QString files = formatInputOutputLabel(m_inputLabel, m_outputLabel, !m_outputCreated); return files + QLatin1String(": ") + makeOverview(makeResultOverview(m_sresult, m_eresult)); } QString SignEncryptFilesResult::details() const { return errorString(); } -int SignEncryptFilesResult::errorCode() const +GpgME::Error SignEncryptFilesResult::error() const { if (m_sresult.error().code()) { - return m_sresult.error().encodedError(); + return m_sresult.error(); } if (m_eresult.error().code()) { - return m_eresult.error().encodedError(); + return m_eresult.error(); } - return 0; + return {}; } QString SignEncryptFilesResult::errorString() const { const bool sign = !m_sresult.isNull(); const bool encrypt = !m_eresult.isNull(); kleo_assert(sign || encrypt); if (sign && encrypt) { return m_sresult.error().code() ? makeResultDetails(m_sresult, m_inputErrorString, m_outputErrorString) : m_eresult.error().code() ? makeResultDetails(m_eresult, m_inputErrorString, m_outputErrorString) : QString(); } return sign ? makeResultDetails(m_sresult, m_inputErrorString, m_outputErrorString) : /*else*/ makeResultDetails(m_eresult, m_inputErrorString, m_outputErrorString); } Task::Result::VisualCode SignEncryptFilesResult::code() const { if (m_sresult.error().isCanceled() || m_eresult.error().isCanceled()) { return Warning; } return (m_sresult.error().code() || m_eresult.error().code()) ? NeutralError : NeutralSuccess; } AuditLog SignEncryptFilesResult::auditLog() const { return m_auditLog; } #include "moc_signencrypttask.cpp" diff --git a/src/crypto/task.cpp b/src/crypto/task.cpp index f19ccb806..b19dd4485 100644 --- a/src/crypto/task.cpp +++ b/src/crypto/task.cpp @@ -1,235 +1,235 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/task.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "task.h" #include "task_p.h" #include "kleopatra_debug.h" #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace GpgME; namespace { class ErrorResult : public Task::Result { public: - ErrorResult(int code, const QString &details) - : Task::Result(), m_code(code), m_details(details) {} + ErrorResult(const GpgME::Error &error, const QString &details) + : Task::Result(), m_error(error), m_details(details) {} QString overview() const override { return makeOverview(m_details); } QString details() const override { return QString(); } - int errorCode() const override + GpgME::Error error() const override { - return m_code; + return m_error; } QString errorString() const override { return m_details; } VisualCode code() const override { return NeutralError; } AuditLog auditLog() const override { return AuditLog(); } private: - const int m_code; + const GpgME::Error m_error; const QString m_details; }; } class Task::Private { friend class ::Kleo::Crypto::Task; Task *const q; public: explicit Private(Task *qq); private: QString m_progressLabel; int m_progress; int m_totalProgress; bool m_asciiArmor; int m_id; }; namespace { static int nextTaskId = 0; } Task::Private::Private(Task *qq) : q(qq), m_progressLabel(), m_progress(0), m_totalProgress(0), m_asciiArmor(false), m_id(nextTaskId++) { } Task::Task(QObject *p) : QObject(p), d(new Private(this)) { } Task::~Task() {} void Task::setAsciiArmor(bool armor) { d->m_asciiArmor = armor; } bool Task::asciiArmor() const { return d->m_asciiArmor; } -std::shared_ptr Task::makeErrorTask(int code, const QString &details, const QString &label) +std::shared_ptr Task::makeErrorTask(const GpgME::Error &error, const QString &details, const QString &label) { const std::shared_ptr t(new SimpleTask(label)); - t->setResult(t->makeErrorResult(code, details)); + t->setResult(t->makeErrorResult(error, details)); return t; } int Task::id() const { return d->m_id; } int Task::currentProgress() const { return d->m_progress; } int Task::totalProgress() const { return d->m_totalProgress; } QString Task::tag() const { return QString(); } QString Task::progressLabel() const { return d->m_progressLabel; } void Task::setProgress(const QString &label, int processed, int total) { d->m_progress = processed; d->m_totalProgress = total; d->m_progressLabel = label; Q_EMIT progress(label, processed, total, QPrivateSignal()); } void Task::start() { try { doStart(); } catch (const Kleo::Exception &e) { - QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(int, e.error().encodedError()), Q_ARG(QString, e.message())); + QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(GpgME::Error, e.error()), Q_ARG(QString, e.message())); } catch (const GpgME::Exception &e) { - QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(int, e.error().encodedError()), Q_ARG(QString, QString::fromLocal8Bit(e.what()))); + QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(GpgME::Error, e.error()), Q_ARG(QString, QString::fromLocal8Bit(e.what()))); } catch (const std::exception &e) { - QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(int, makeGnuPGError(GPG_ERR_UNEXPECTED)), Q_ARG(QString, QString::fromLocal8Bit(e.what()))); + QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(GpgME::Error, Error::fromCode(GPG_ERR_UNEXPECTED)), Q_ARG(QString, QString::fromLocal8Bit(e.what()))); } catch (...) { - QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(int, makeGnuPGError(GPG_ERR_UNEXPECTED)), Q_ARG(QString, i18n("Unknown exception in Task::start()"))); + QMetaObject::invokeMethod(this, "emitError", Qt::QueuedConnection, Q_ARG(GpgME::Error, Error::fromCode(GPG_ERR_UNEXPECTED)), Q_ARG(QString, i18n("Unknown exception in Task::start()"))); } Q_EMIT started(QPrivateSignal()); } -void Task::emitError(int errCode, const QString &details) +void Task::emitError(const GpgME::Error &error, const QString &details) { - emitResult(makeErrorResult(errCode, details)); + emitResult(makeErrorResult(error, details)); } void Task::emitResult(const std::shared_ptr &r) { d->m_progress = d->m_totalProgress; Q_EMIT progress(progressLabel(), currentProgress(), totalProgress(), QPrivateSignal()); Q_EMIT result(r, QPrivateSignal()); } -std::shared_ptr Task::makeErrorResult(int errCode, const QString &details) +std::shared_ptr Task::makeErrorResult(const GpgME::Error &error, const QString &details) { - return std::shared_ptr(new ErrorResult(errCode, details)); + return std::shared_ptr(new ErrorResult(error, details)); } class Task::Result::Private { public: Private() {} }; Task::Result::Result() : d(new Private()) {} Task::Result::~Result() {} bool Task::Result::hasError() const { - return errorCode() != 0; + return error().code() != 0; } static QString image(const char *img) { // ### escape? return KIconLoader::global()->iconPath(QLatin1String(img), KIconLoader::Small); } QString Task::Result::makeOverview(const QString &msg) { return QLatin1String("") + msg + QLatin1String(""); } QString Task::Result::iconPath(VisualCode code) { switch (code) { case Danger: return image("dialog-error"); case AllGood: return image("dialog-ok"); case Warning: return image("dialog-warning"); case NeutralError: case NeutralSuccess: default: return QString(); } } QString Task::Result::icon() const { return iconPath(code()); } #include "moc_task_p.cpp" diff --git a/src/crypto/task.h b/src/crypto/task.h index 3f9848472..999cb7c7a 100644 --- a/src/crypto/task.h +++ b/src/crypto/task.h @@ -1,131 +1,131 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/task.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include #include namespace Kleo { class AuditLog; } namespace Kleo { namespace Crypto { class Task : public QObject { Q_OBJECT public: explicit Task(QObject *parent = nullptr); ~Task() override; class Result; void setAsciiArmor(bool armor); bool asciiArmor() const; virtual GpgME::Protocol protocol() const = 0; void start(); virtual QString label() const = 0; virtual QString tag() const; QString progressLabel() const; int currentProgress() const; int totalProgress() const; int id() const; - static std::shared_ptr makeErrorTask(int code, const QString &details, const QString &label); + static std::shared_ptr makeErrorTask(const GpgME::Error &error, const QString &details, const QString &label); public Q_SLOTS: virtual void cancel() = 0; Q_SIGNALS: void progress(const QString &what, int processed, int total, QPrivateSignal); void result(const std::shared_ptr &, QPrivateSignal); void started(QPrivateSignal); protected: - std::shared_ptr makeErrorResult(int errCode, const QString &details); + std::shared_ptr makeErrorResult(const GpgME::Error &error, const QString &details); void emitResult(const std::shared_ptr &result); protected Q_SLOTS: void setProgress(const QString &msg, int processed, int total); private Q_SLOTS: - void emitError(int errCode, const QString &details); + void emitError(const GpgME::Error &error, const QString &details); private: virtual void doStart() = 0; virtual unsigned long long inputSize() const = 0; private: class Private; kdtools::pimpl_ptr d; }; class Task::Result { const QString m_nonce; public: Result(); virtual ~Result(); const QString &nonce() const { return m_nonce; } bool hasError() const; enum VisualCode { AllGood, Warning, Danger, NeutralSuccess, NeutralError }; virtual QString icon() const; virtual QString overview() const = 0; virtual QString details() const = 0; - virtual int errorCode() const = 0; + virtual GpgME::Error error() const = 0; virtual QString errorString() const = 0; virtual VisualCode code() const = 0; virtual AuditLog auditLog() const = 0; virtual QPointer parentTask() const {return QPointer();} protected: static QString iconPath(VisualCode code); static QString makeOverview(const QString &msg); private: class Private; kdtools::pimpl_ptr d; }; } } diff --git a/src/view/padwidget.cpp b/src/view/padwidget.cpp index f54b7cc8e..7f0631b91 100644 --- a/src/view/padwidget.cpp +++ b/src/view/padwidget.cpp @@ -1,547 +1,547 @@ /* -*- mode: c++; c-basic-offset:4 -*- padwidget.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2018 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include "padwidget.h" #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include "crypto/gui/signencryptwidget.h" #include "crypto/gui/resultitemwidget.h" #include "crypto/signencrypttask.h" #include "crypto/decryptverifytask.h" #include #include "utils/input.h" #include "utils/output.h" #include "commands/importcertificatefromdatacommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Crypto; using namespace Kleo::Crypto::Gui; static GpgME::Protocol getProtocol(const std::shared_ptr &result) { const auto dvResult = dynamic_cast(result.get()); if (dvResult) { for (const auto &key: KeyCache::instance()->findRecipients(dvResult->decryptionResult())) { return key.protocol(); } for (const auto &key: KeyCache::instance()->findSigners(dvResult->verificationResult())) { return key.protocol(); } } return GpgME::UnknownProtocol; } class PadWidget::Private { friend class ::Kleo::PadWidget; public: Private(PadWidget *qq): q(qq), mEdit(new QTextEdit), mCryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-sign-encrypt")), i18n("Sign / Encrypt Notepad"))), mDecryptBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("document-edit-decrypt-verify")), i18n("Decrypt / Verify Notepad"))), mImportBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("view-certificate-import")), i18n("Import Notepad"))), mRevertBtn(new QPushButton(QIcon::fromTheme(QStringLiteral("edit-undo")), i18n("Revert"))), mMessageWidget{new KMessageWidget}, mAdditionalInfoLabel(new QLabel), mSigEncWidget(new SignEncryptWidget(nullptr, true)), mProgressBar(new QProgressBar), mProgressLabel(new QLabel), mLastResultWidget(nullptr), mPGPRB(nullptr), mCMSRB(nullptr), mImportProto(GpgME::UnknownProtocol) { auto vLay = new QVBoxLayout(q); auto btnLay = new QHBoxLayout; vLay->addLayout(btnLay); btnLay->addWidget(mCryptBtn); btnLay->addWidget(mDecryptBtn); btnLay->addWidget(mImportBtn); btnLay->addWidget(mRevertBtn); mRevertBtn->setVisible(false); btnLay->addWidget(mAdditionalInfoLabel); btnLay->addStretch(-1); mMessageWidget->setMessageType(KMessageWidget::Warning); mMessageWidget->setIcon(q->style()->standardIcon(QStyle::SP_MessageBoxWarning, nullptr, q)); mMessageWidget->setText(i18n("Signing and encryption is not possible.")); mMessageWidget->setToolTip(xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "You cannot use Kleopatra for signing or encryption " "because the GnuPG system used by Kleopatra is not %1.", DeVSCompliance::name(true))); mMessageWidget->setCloseButtonVisible(false); mMessageWidget->setVisible(false); vLay->addWidget(mMessageWidget); mProgressBar->setRange(0, 0); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); auto progLay = new QHBoxLayout; progLay->addWidget(mProgressLabel); progLay->addWidget(mProgressBar); mStatusLay = new QVBoxLayout; mStatusLay->addLayout(progLay); vLay->addLayout(mStatusLay, 0); auto tabWidget = new QTabWidget; vLay->addWidget(tabWidget, 1); tabWidget->addTab(mEdit, QIcon::fromTheme(QStringLiteral("edittext")), i18n("Notepad")); // The recipients area auto recipientsWidget = new QWidget; auto recipientsVLay = new QVBoxLayout(recipientsWidget); auto protocolSelectionLay = new QHBoxLayout; bool pgpOnly = KeyCache::instance()->pgpOnly(); if (!pgpOnly) { recipientsVLay->addLayout(protocolSelectionLay); } protocolSelectionLay->addWidget(new QLabel(i18n("

Protocol:

"))); protocolSelectionLay->addStretch(-1); // Once S/MIME is supported add radio for S/MIME here. recipientsVLay->addWidget(mSigEncWidget); tabWidget->addTab(recipientsWidget, QIcon::fromTheme(QStringLiteral("contact-new-symbolic")), i18n("Recipients")); mEdit->setPlaceholderText(i18n("Enter a message to encrypt or decrypt...")); auto fixedFont = QFont(QStringLiteral("Monospace")); fixedFont.setStyleHint(QFont::TypeWriter); // This does not work well // QFontDatabase::systemFont(QFontDatabase::FixedFont); mEdit->setFont(fixedFont); mEdit->setAcceptRichText(false); mEdit->setMinimumWidth(QFontMetrics(fixedFont).averageCharWidth() * 70); if (KeyCache::instance()->pgpOnly() || !Settings{}.cmsEnabled()) { mSigEncWidget->setProtocol(GpgME::OpenPGP); } else { auto grp = new QButtonGroup(q); auto mPGPRB = new QRadioButton(i18n("OpenPGP")); auto mCMSRB = new QRadioButton(i18n("S/MIME")); grp->addButton(mPGPRB); grp->addButton(mCMSRB); KConfigGroup config(KSharedConfig::openConfig(), "Notepad"); if (config.readEntry("wasCMS", false)) { mCMSRB->setChecked(true); mSigEncWidget->setProtocol(GpgME::CMS); } else { mPGPRB->setChecked(true); mSigEncWidget->setProtocol(GpgME::OpenPGP); } protocolSelectionLay->addWidget(mPGPRB); protocolSelectionLay->addWidget(mCMSRB); connect(mPGPRB, &QRadioButton::toggled, q, [this] (bool value) { if (value) { mSigEncWidget->setProtocol(GpgME::OpenPGP); } }); connect(mCMSRB, &QRadioButton::toggled, q, [this] (bool value) { if (value) { mSigEncWidget->setProtocol(GpgME::CMS); } }); } updateButtons(); connect(mEdit, &QTextEdit::textChanged, q, [this] () { updateButtons(); }); connect(mCryptBtn, &QPushButton::clicked, q, [this] () { doEncryptSign(); }); connect(mSigEncWidget, &SignEncryptWidget::operationChanged, q, [this]() { updateButtons(); }); connect(mDecryptBtn, &QPushButton::clicked, q, [this] () { doDecryptVerify(); }); connect(mImportBtn, &QPushButton::clicked, q, [this]() { doImport(); }); connect(mRevertBtn, &QPushButton::clicked, q, [this] () { revert(); }); } void revert() { mEdit->setPlainText(QString::fromUtf8(mInputData)); mRevertBtn->setVisible(false); } void updateRecipientsFromResult(const Kleo::Crypto::DecryptVerifyResult &result) { const auto decResult = result.decryptionResult(); for (const auto &recipient: decResult.recipients()) { if (!recipient.keyID()) { continue; } GpgME::Key key; if (strlen(recipient.keyID()) < 16) { key = KeyCache::instance()->findByShortKeyID(recipient.keyID()); } else { key = KeyCache::instance()->findByKeyIDOrFingerprint(recipient.keyID()); } if (key.isNull()) { std::vector subids; subids.push_back(std::string(recipient.keyID())); for (const auto &subkey: KeyCache::instance()->findSubkeysByKeyID(subids)) { key = subkey.parent(); break; } } if (key.isNull()) { qCDebug(KLEOPATRA_LOG) << "Unknown key" << recipient.keyID(); mSigEncWidget->addUnknownRecipient(recipient.keyID()); continue; } bool keyFound = false; for (const auto &existingKey: mSigEncWidget->recipients()) { if (existingKey.primaryFingerprint() && key.primaryFingerprint() && !strcmp (existingKey.primaryFingerprint(), key.primaryFingerprint())) { keyFound = true; break; } } if (!keyFound) { mSigEncWidget->addRecipient(key); } } } void cryptDone(const std::shared_ptr &result) { updateButtons(); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); mLastResultWidget = new ResultItemWidget(result); mLastResultWidget->showCloseButton(true); mStatusLay->addWidget(mLastResultWidget); connect(mLastResultWidget, &ResultItemWidget::closeButtonClicked, q, [this] () { removeLastResultItem(); }); // Check result protocol if (mPGPRB) { auto proto = getProtocol(result); if (proto == GpgME::UnknownProtocol) { proto = mPGPRB->isChecked() ? GpgME::OpenPGP : GpgME::CMS; } else if (proto == GpgME::OpenPGP) { mPGPRB->setChecked(true); } else if (proto == GpgME::CMS) { mCMSRB->setChecked(true); } KConfigGroup config(KSharedConfig::openConfig(), "Notepad"); config.writeEntry("wasCMS", proto == GpgME::CMS); } - if (result->errorCode()) { + if (result->error().code()) { if (!result->errorString().isEmpty()) { KMessageBox::error(q, result->errorString(), i18nc("@title", "Error in crypto action")); } return; } mEdit->setPlainText(QString::fromUtf8(mOutputData)); mOutputData.clear(); mRevertBtn->setVisible(true); const auto decryptVerifyResult = dynamic_cast(result.get()); if (decryptVerifyResult) { updateRecipientsFromResult(*decryptVerifyResult); } } void doDecryptVerify() { doCryptoCommon(); mSigEncWidget->clearAddedRecipients(); mProgressLabel->setText(i18n("Decrypt / Verify") + QStringLiteral("...")); auto input = Input::createFromByteArray(&mInputData, i18n("Notepad")); auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad")); AbstractDecryptVerifyTask *task; auto classification = input->classification(); if (classification & Class::OpaqueSignature || classification & Class::ClearsignedMessage) { auto verifyTask = new VerifyOpaqueTask(); verifyTask->setInput(input); verifyTask->setOutput(output); task = verifyTask; } else { auto decTask = new DecryptVerifyTask(); decTask->setInput(input); decTask->setOutput(output); task = decTask; } try { task->autodetectProtocolFromInput(); } catch (const Kleo::Exception &e) { KMessageBox::error(q, e.message(), i18nc("@title", "Error in crypto action")); updateButtons(); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); return; } connect (task, &Task::result, q, [this, task] (const std::shared_ptr &result) { - qCDebug(KLEOPATRA_LOG) << "Decrypt / Verify done. Err:" << result->errorCode(); + qCDebug(KLEOPATRA_LOG) << "Decrypt / Verify done. Err:" << result->error().code(); task->deleteLater(); cryptDone(result); }); task->start(); } void removeLastResultItem() { if (mLastResultWidget) { mStatusLay->removeWidget(mLastResultWidget); delete mLastResultWidget; mLastResultWidget = nullptr; } } void doCryptoCommon() { mCryptBtn->setEnabled(false); mDecryptBtn->setEnabled(false); mImportBtn->setEnabled(false); mProgressBar->setVisible(true); mProgressLabel->setVisible(true); mInputData = mEdit->toPlainText().toUtf8(); removeLastResultItem(); } void doEncryptSign() { if (DeVSCompliance::isActive() && !DeVSCompliance::isCompliant()) { KMessageBox::error(q->topLevelWidget(), xi18nc("@info %1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant", "Sorry! You cannot use Kleopatra for signing or encryption " "because the GnuPG system used by Kleopatra is not %1.", DeVSCompliance::name(true))); return; } doCryptoCommon(); switch (mSigEncWidget->currentOp()) { case SignEncryptWidget::Sign: mProgressLabel->setText(i18nc("@info:progress", "Signing notepad...")); break; case SignEncryptWidget::Encrypt: mProgressLabel->setText(i18nc("@info:progress", "Encrypting notepad...")); break; case SignEncryptWidget::SignAndEncrypt: mProgressLabel->setText(i18nc("@info:progress", "Signing and encrypting notepad...")); break; default: ; }; auto input = Input::createFromByteArray(&mInputData, i18n("Notepad")); auto output = Output::createFromByteArray(&mOutputData, i18n("Notepad")); auto task = new SignEncryptTask(); task->setInput(input); task->setOutput(output); const auto sigKey = mSigEncWidget->signKey(); const std::vector recipients = mSigEncWidget->recipients(); const bool encrypt = mSigEncWidget->encryptSymmetric() || !recipients.empty(); const bool sign = !sigKey.isNull(); if (sign) { task->setSign(true); std::vector signVector; signVector.push_back(sigKey); task->setSigners(signVector); } else { task->setSign(false); } task->setEncrypt(encrypt); task->setRecipients(recipients); task->setEncryptSymmetric(mSigEncWidget->encryptSymmetric()); task->setAsciiArmor(true); if (sign && !encrypt && sigKey.protocol() == GpgME::OpenPGP) { task->setClearsign(true); } connect (task, &Task::result, q, [this, task] (const std::shared_ptr &result) { - qCDebug(KLEOPATRA_LOG) << "Encrypt / Sign done. Err:" << result->errorCode(); + qCDebug(KLEOPATRA_LOG) << "Encrypt / Sign done. Err:" << result->error().code(); task->deleteLater(); cryptDone(result); }); task->start(); } void doImport() { doCryptoCommon(); mProgressLabel->setText(i18n("Importing...")); auto cmd = new Kleo::ImportCertificateFromDataCommand(mInputData, mImportProto); connect(cmd, &Kleo::ImportCertificatesCommand::finished, q, [this] () { updateButtons(); mProgressBar->setVisible(false); mProgressLabel->setVisible(false); mRevertBtn->setVisible(true); mEdit->setPlainText(QString()); }); cmd->start(); } void checkImportProtocol() { QGpgME::QByteArrayDataProvider dp(mEdit->toPlainText().toUtf8()); GpgME::Data data(&dp); auto type = data.type(); if (type == GpgME::Data::PGPKey) { mImportProto = GpgME::OpenPGP; } else if (type == GpgME::Data::X509Cert || type == GpgME::Data::PKCS12) { mImportProto = GpgME::CMS; } else { mImportProto = GpgME::UnknownProtocol; } } void updateButtons() { mAdditionalInfoLabel->setVisible(false); mDecryptBtn->setEnabled(mEdit->document() && !mEdit->document()->isEmpty()); checkImportProtocol(); mImportBtn->setEnabled(mImportProto != GpgME::UnknownProtocol); mCryptBtn->setEnabled(mSigEncWidget->currentOp() != SignEncryptWidget::NoOperation); switch (mSigEncWidget->currentOp()) { case SignEncryptWidget::Sign: mCryptBtn->setText(i18nc("@action:button", "Sign Notepad")); break; case SignEncryptWidget::Encrypt: mCryptBtn->setText(i18nc("@action:button", "Encrypt Notepad")); break; case SignEncryptWidget::SignAndEncrypt: default: mCryptBtn->setText(i18nc("@action:button", "Sign / Encrypt Notepad")); }; if (DeVSCompliance::isActive()) { const bool de_vs = DeVSCompliance::isCompliant() && mSigEncWidget->isDeVsAndValid(); DeVSCompliance::decorate(mCryptBtn, de_vs); mAdditionalInfoLabel->setText(DeVSCompliance::name(de_vs)); mAdditionalInfoLabel->setVisible(true); if (!DeVSCompliance::isCompliant()) { mCryptBtn->setEnabled(false); } mMessageWidget->setVisible(!DeVSCompliance::isCompliant()); } } private: PadWidget *const q; QTextEdit *mEdit; QPushButton *mCryptBtn; QPushButton *mDecryptBtn; QPushButton *mImportBtn; QPushButton *mRevertBtn; KMessageWidget *mMessageWidget; QLabel *mAdditionalInfoLabel; QByteArray mInputData; QByteArray mOutputData; SignEncryptWidget *mSigEncWidget; QProgressBar *mProgressBar; QLabel *mProgressLabel; QVBoxLayout *mStatusLay; ResultItemWidget *mLastResultWidget; QList mAutoAddedKeys; QRadioButton *mPGPRB; QRadioButton *mCMSRB; GpgME::Protocol mImportProto; }; PadWidget::PadWidget(QWidget *parent): QWidget(parent), d(new Private(this)) { } void PadWidget::focusFirstChild(Qt::FocusReason reason) { d->mEdit->setFocus(reason); }