diff --git a/src/crypto/decryptverifytask.cpp b/src/crypto/decryptverifytask.cpp
index 6e187b72e..41f7c557b 100644
--- a/src/crypto/decryptverifytask.cpp
+++ b/src/crypto/decryptverifytask.cpp
@@ -1,1552 +1,1552 @@
 /* -*- 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 <config-kleopatra.h>
 
 #include "decryptverifytask.h"
 
 #include <QGpgME/DecryptJob>
 #include <QGpgME/DecryptVerifyArchiveJob>
 #include <QGpgME/DecryptVerifyJob>
 #include <QGpgME/Protocol>
 #include <QGpgME/VerifyDetachedJob>
 #include <QGpgME/VerifyOpaqueJob>
 
 #include <Libkleo/AuditLogEntry>
 #include <Libkleo/Classify>
 #include <Libkleo/Compliance>
 #include <Libkleo/Dn>
 #include <Libkleo/Formatting>
 #include <Libkleo/KeyCache>
 #include <Libkleo/KleoException>
 #include <Libkleo/Predicates>
 #include <Libkleo/Stl_Util>
 
 #include <Libkleo/GnuPG>
 #include <utils/detail_p.h>
 #include <utils/input.h>
 #include <utils/kleo_assert.h>
 #include <utils/output.h>
 
 #include <KEmailAddress>
 #include <KMime/Types>
 
 #include <gpgme++/context.h>
 #include <gpgme++/decryptionresult.h>
 #include <gpgme++/error.h>
 #include <gpgme++/key.h>
 #include <gpgme++/verificationresult.h>
 
 #include <gpg-error.h>
 
 #include "kleopatra_debug.h"
 
 #include <KFileUtils>
 #include <KLocalizedString>
 
 #include <QByteArray>
 #include <QDateTime>
 #include <QDir>
 #include <QFile>
 #include <QFileInfo>
 #include <QIODevice>
 #include <QLocale>
 #include <QMimeDatabase>
 #include <QStringList>
 
 #include <algorithm>
 #include <sstream>
 
 using namespace Kleo::Crypto;
 using namespace Kleo;
 using namespace GpgME;
 using namespace KMime::Types;
 using namespace Qt::Literals::StringLiterals;
 
 using namespace Qt::Literals::StringLiterals;
 
 namespace
 {
 
 static AuditLogEntry auditLogFromSender(QObject *sender)
 {
     return AuditLogEntry::fromJob(qobject_cast<const QGpgME::Job *>(sender));
 }
 
 static std::vector<QString> extractEmails(const Key &key)
 {
     std::vector<QString> res;
     const auto userIDs{key.userIDs()};
     for (const UserID &id : userIDs) {
         const auto email = Kleo::Formatting::email(id);
         if (!email.isEmpty()) {
             res.push_back(email);
         }
     }
     return res;
 }
 
 static bool keyContainsEmail(const Key &key, const QString &email)
 {
     return std::ranges::any_of(extractEmails(key), [email](const QString &emailItem) {
         return emailItem.compare(email, Qt::CaseInsensitive) == 0;
     });
 }
 
 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);
     }
 }
 
 static QString ensureUniqueDirectory(const QString &path)
 {
     // make sure that we don't use an existing directory
     QString uniquePath = path;
     const QFileInfo outputInfo{path};
     if (outputInfo.exists()) {
         const auto uniqueName = KFileUtils::suggestName(QUrl::fromLocalFile(outputInfo.absolutePath()), outputInfo.fileName());
         uniquePath = outputInfo.dir().filePath(uniqueName);
     }
     if (!QDir{}.mkpath(uniquePath)) {
         return {};
     }
     return uniquePath;
 }
 
 static bool mimeTypeInherits(const QMimeType &mimeType, const QString &mimeTypeName)
 {
     // inherits is expensive on an invalid mimeType
     return mimeType.isValid() && mimeType.inherits(mimeTypeName);
 }
 }
 
 namespace
 {
 
 static QString formatRecipientsDetails(const std::vector<Key> &knownRecipients, unsigned int numRecipients)
 {
     if (numRecipients == 0) {
         return {};
     }
 
     QString details = i18np("Recipient:", "Recipients:", numRecipients);
 
     if (numRecipients == 1) {
         if (knownRecipients.empty()) {
             details += QLatin1Char(' ') + i18nc("@info", "One unknown recipient");
         } else {
             details += QLatin1Char(' ') + Formatting::summaryLine(knownRecipients.front()).toHtmlEscaped();
         }
     } else {
         details += QLatin1StringView("<ul>");
         for (const Key &key : knownRecipients) {
             details += QLatin1StringView("<li>") + Formatting::summaryLine(key).toHtmlEscaped() + QLatin1StringView("</li>");
         }
         if (knownRecipients.size() < numRecipients) {
             details += QLatin1StringView("<li>") + i18np("One unknown recipient", "%1 unknown recipients", numRecipients - knownRecipients.size())
                 + QLatin1StringView("</li>");
         }
         details += QLatin1StringView("</ul>");
     }
 
     return details;
 }
 
 } // anon namespace
 
 class DecryptVerifyResult::Private
 {
     DecryptVerifyResult *const q;
 
 public:
     Private(const VerificationResult &vr,
             const DecryptionResult &dr,
             const QByteArray &stuff,
             const QString &fileName,
             const GpgME::Error &error,
             const QString &errString,
             const QString &input,
             const QString &output,
             const AuditLogEntry &auditLog,
             Task *parentTask,
             const Mailbox &informativeSender,
             bool isNotepad,
             DecryptVerifyResult *qq)
         : q(qq)
         , m_verificationResult(vr)
         , m_decryptionResult(dr)
         , m_stuff(stuff)
         , m_fileName(fileName)
         , m_error(error)
         , m_errorString(errString)
         , m_inputLabel(input)
         , m_outputLabel(output)
         , m_auditLog(auditLog)
         , m_parentTask(QPointer<Task>(parentTask))
         , m_informativeSender(informativeSender)
     {
         q->setIsNotepad(isNotepad);
     }
 
     QString label() const
     {
         const auto verify = m_verificationResult.numSignatures() > 0;
         const auto decrypt = !m_decryptionResult.isNull();
         const auto recipients = KeyCache::instance()->findRecipients(m_decryptionResult);
 
         Q_ASSERT(verify || decrypt);
 
         Error error;
         if (m_error.code()) {
             error = m_error;
         } else if (m_decryptionResult.error().code()) {
             error = m_decryptionResult.error();
         } else {
             error = m_verificationResult.error();
         }
 
         QString label;
         if (verify && decrypt) {
             if (error.isCanceled()) {
                 return i18nc("@info", "Decryption and verification of <filename>%1</filename> canceled.", m_inputLabel);
             } else if (error.code() == GPG_ERR_NO_SECKEY) {
-                label = xi18nc("@info Unable to decrypt and verify <file>: <reason>", "Unable to decrypt and verify <filename>%1</filename>:", m_inputLabel);
+                label = xi18nc("@info Unable to decrypt and verify <file>:", "Unable to decrypt and verify <filename>%1</filename>:", m_inputLabel);
             } else if (error.code() != GPG_ERR_NO_ERROR) {
-                label = xi18nc("@info Failed to decrypt and verify <file>: <reason>", "Failed to decrypt and verify <filename>%1</filename>:", m_inputLabel);
+                label = xi18nc("@info Failed to decrypt and verify <file>:", "Failed to decrypt and verify <filename>%1</filename>:", m_inputLabel);
             } else {
                 label = xi18nc("@info Successfully decrypted and verified <file> as <file>.",
                                "Successfully decrypted and verified <filename>%1</filename> as <filename>%2</filename>.",
                                m_inputLabel,
                                m_outputLabel);
             }
         } else if (verify) {
             if (error.isCanceled()) {
                 return i18nc("@info", "Verification of <filename>%1</filename> canceled.", m_inputLabel);
             } else if (error) {
-                label = xi18nc("@info Failed to verify <file>: <reason>", "Failed to verify <filename>%1</filename>:", m_inputLabel);
+                label = xi18nc("@info Failed to verify <file>:", "Failed to verify <filename>%1</filename>:", m_inputLabel);
             } else {
                 label = xi18nc("@info Verified <file> with signature in <file>.",
                                "Verified <filename>%1</filename> with signature in <filename>%2</filename>.",
                                m_outputLabel,
                                m_inputLabel);
             }
         } else {
             if (error.isCanceled()) {
                 return i18nc("@info", "Decryption of <filename>%1</filename> canceled.", m_inputLabel);
             } else if (error.code() == GPG_ERR_NO_SECKEY) {
-                label = xi18nc("@info Unable to decrypt <file>: <reason>", "Unable to decrypt <filename>%1</filename>:", m_inputLabel);
+                label = xi18nc("@info Unable to decrypt <file>:", "Unable to decrypt <filename>%1</filename>:", m_inputLabel);
             } else if (error.code() != GPG_ERR_NO_ERROR) {
-                label = xi18nc("@info Failed to decrypt <file>: <reason>", "Failed to decrypt <filename>%1</filename>:", m_inputLabel);
+                label = xi18nc("@info Failed to decrypt <file>:", "Failed to decrypt <filename>%1</filename>:", m_inputLabel);
             } else {
                 label = xi18nc("@info Successfully decrypted <file> as <file>.",
                                "Successfully decrypted <filename>%1</filename> as <filename>%2</filename>.",
                                m_inputLabel,
                                m_outputLabel);
             }
         }
 
         if (error) {
             label += u' ' + Formatting::errorAsString(error) + u'.';
             if (error.code() == GPG_ERR_NO_SECKEY) {
                 label += "<br />"_L1
                     + i18nc("@info",
                             "The data was not encrypted for any "
                             "secret key in your certificate list.");
             }
         } else if (m_decryptionResult.isLegacyCipherNoMDC()) {
             label += u' ' + i18n("No integrity protection (MDC).");
         } else if (!m_errorString.isEmpty()) {
             if (error.code()) {
                 label += u' ' + Formatting::errorAsString(error) + ": "_L1;
             }
             label += m_errorString.toHtmlEscaped();
         }
 
         if (error) {
             return label;
         }
 
         if (DeVSCompliance::isCompliant()) {
             label += ((m_decryptionResult.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 <b>is not</b> %1.",
                                    DeVSCompliance::name(true))));
         }
 
         if (m_decryptionResult.fileName()) {
             const auto decVerifyTask = qobject_cast<AbstractDecryptVerifyTask *>(m_parentTask.data());
             if (decVerifyTask) {
                 const auto embedFileName = QString::fromUtf8(m_decryptionResult.fileName()).toHtmlEscaped();
 
                 if (embedFileName != decVerifyTask->outputLabel()) {
                     label += "<br />"_L1 + i18n("Embedded file name: '%1'", embedFileName);
                 }
             }
         }
 
         if (!verify) {
             label += "<br/>"_L1 + i18n("<b>Note:</b> You cannot be sure who encrypted this message as it is not signed.");
         }
 
         if (m_decryptionResult.isLegacyCipherNoMDC()) {
             label += i18nc("Integrity protection was missing because an old cipher was used.",
                            "<b>Hint:</b> 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("<br/><br/>")
                 + 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("<br/><br/>");
         }
 
         if (decrypt) {
             label += "<br/>"_L1 + formatRecipientsDetails(recipients, m_decryptionResult.numRecipients());
         }
 
         return label;
     }
 
     VerificationResult m_verificationResult;
     DecryptionResult m_decryptionResult;
     QByteArray m_stuff;
     QString m_fileName;
     GpgME::Error m_error;
     QString m_errorString;
     QString m_inputLabel;
     QString m_outputLabel;
     const AuditLogEntry m_auditLog;
     QPointer<Task> m_parentTask;
     const Mailbox m_informativeSender;
 };
 
 std::shared_ptr<DecryptVerifyResult>
 AbstractDecryptVerifyTask::fromDecryptResult(const DecryptionResult &dr, const QByteArray &plaintext, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(VerificationResult(), //
                                                                         dr,
                                                                         plaintext,
                                                                         {},
                                                                         {},
                                                                         QString(),
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptResult(const GpgME::Error &err, const QString &what, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(VerificationResult(), //
                                                                         DecryptionResult(err),
                                                                         QByteArray(),
                                                                         {},
                                                                         err,
                                                                         what,
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptVerifyResult(const DecryptionResult &dr,
                                                                                         const VerificationResult &vr,
                                                                                         const QByteArray &plaintext,
                                                                                         const QString &fileName,
                                                                                         const AuditLogEntry &auditLog)
 {
     const auto err = dr.error().code() ? dr.error() : vr.error();
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(vr, //
                                                                         dr,
                                                                         plaintext,
                                                                         fileName,
                                                                         err,
                                                                         QString(),
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 std::shared_ptr<DecryptVerifyResult>
 AbstractDecryptVerifyTask::fromDecryptVerifyResult(const GpgME::Error &err, const QString &details, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(VerificationResult(), //
                                                                         DecryptionResult(err),
                                                                         QByteArray(),
                                                                         {},
                                                                         err,
                                                                         details,
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 std::shared_ptr<DecryptVerifyResult>
 AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const VerificationResult &vr, const QByteArray &plaintext, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(vr, //
                                                                         DecryptionResult(),
                                                                         plaintext,
                                                                         {},
                                                                         {},
                                                                         QString(),
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 std::shared_ptr<DecryptVerifyResult>
 AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const GpgME::Error &err, const QString &details, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(VerificationResult(err), //
                                                                         DecryptionResult(),
                                                                         QByteArray(),
                                                                         {},
                                                                         err,
                                                                         details,
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyDetachedResult(const VerificationResult &vr, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(vr, //
                                                                         DecryptionResult(),
                                                                         QByteArray(),
                                                                         {},
                                                                         {},
                                                                         QString(),
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 std::shared_ptr<DecryptVerifyResult>
 AbstractDecryptVerifyTask::fromVerifyDetachedResult(const GpgME::Error &err, const QString &details, const AuditLogEntry &auditLog)
 {
     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(VerificationResult(err), //
                                                                         DecryptionResult(),
                                                                         QByteArray(),
                                                                         {},
                                                                         err,
                                                                         details,
                                                                         inputLabel(),
                                                                         outputLabel(),
                                                                         auditLog,
                                                                         this,
                                                                         informativeSender(),
                                                                         isNotepad()));
 }
 
 DecryptVerifyResult::DecryptVerifyResult(const VerificationResult &vr,
                                          const DecryptionResult &dr,
                                          const QByteArray &stuff,
                                          const QString &fileName,
                                          const GpgME::Error &error,
                                          const QString &errString,
                                          const QString &inputLabel,
                                          const QString &outputLabel,
                                          const AuditLogEntry &auditLog,
                                          Task *parentTask,
                                          const Mailbox &informativeSender,
                                          bool isNotepad)
     : Task::Result()
     , d(new Private(vr, dr, stuff, fileName, error, errString, inputLabel, outputLabel, auditLog, parentTask, informativeSender, isNotepad, this))
 {
 }
 
 Task::Result::ContentType DecryptVerifyResult::viewableContentType() const
 {
     if (decryptionResult().isMime()) {
         return Task::Result::ContentType::Mime;
     }
 
     if (fileName().isEmpty()) {
         return Task::Result::ContentType::None;
     }
 
     if (fileName().endsWith(QStringLiteral("openpgp-encrypted-message"))) {
         return Task::Result::ContentType::Mime;
     }
 
     QMimeDatabase mimeDatabase;
     const auto mimeType = mimeDatabase.mimeTypeForFile(fileName());
     if (mimeTypeInherits(mimeType, QStringLiteral("message/rfc822"))) {
         return Task::Result::ContentType::Mime;
     }
 
     if (mimeTypeInherits(mimeType, QStringLiteral("application/mbox"))) {
         return Task::Result::ContentType::Mbox;
     }
 
     return Task::Result::ContentType::None;
 }
 
 QString DecryptVerifyResult::details() const
 {
     return {};
 }
 
 QString DecryptVerifyResult::overview() const
 {
     const auto decrypting = !d->m_decryptionResult.isNull();
     const auto verifying = d->m_verificationResult.numSignatures() > 0;
 
     if (isNotepad()) {
         if (decrypting && d->m_decryptionResult.error()) {
             return i18nc("@info", "Failed to decrypt the notepad: %1", Formatting::errorAsString(d->m_decryptionResult.error()));
         }
         if (verifying && d->m_verificationResult.error()) {
             return i18nc("@info", "Failed to verify the notepad: %1", Formatting::errorAsString(d->m_verificationResult.error()));
         }
 
         if (decrypting && verifying) {
             return i18nc("@info", "Successfully decrypted and verified the notepad");
         }
         if (decrypting) {
             return i18nc("@info", "Successfully decrypted the notepad");
         }
         if (verifying) {
             return i18nc("@info", "Successfully verified the notepad");
         }
         return {};
     }
 
     return d->label();
 }
 
 static Task::Result::VisualCode codeForSignature(const Signature &signature)
 {
     if (signature.summary() & Signature::Red) {
         return Task::Result::VisualCode::Danger;
     }
-    if (signature.summary() & Signature::Valid || signature.summary() & Signature::Green) {
+    if ((signature.summary() & Signature::Valid) || (signature.summary() & Signature::Green)) {
         return Task::Result::AllGood;
     }
     return Task::Result::Warning;
 }
 
 QList<Task::Result::ResultListItem> DecryptVerifyResult::detailsList() const
 {
     QList<Task::Result::ResultListItem> details;
     for (const Signature &sig : d->m_verificationResult.signatures()) {
         const auto signerKey = KeyCache::instance()->findSigner(sig);
         const auto informativeMailAddress = QString::fromUtf8(d->m_informativeSender.address());
         auto text = Kleo::Formatting::prettySignature(sig, informativeMailAddress);
         if (!informativeMailAddress.isEmpty() && !signerKey.isNull() && !keyContainsEmail(signerKey, informativeMailAddress)) {
             QString emailsList;
             for (const auto &email : extractEmails(signerKey)) {
                 emailsList += "<li>"_L1 + email + "</li>"_L1;
             }
             text += "<br />"_L1
                 + i18nc("@info",
                         "Warning: The sender's mail address is not stored in the <a href=\"key:%1\">certificate</a> used for signing. Stored:<ul>%2</ul>",
                         QString::fromLatin1(sig.key().primaryFingerprint()),
                         emailsList);
         }
         details += Task::Result::ResultListItem{
             .details = text,
             .code = codeForSignature(sig),
         };
     }
     return details;
 }
 
 GpgME::Error DecryptVerifyResult::error() const
 {
     return d->m_error;
 }
 
 QString DecryptVerifyResult::errorString() const
 {
     return d->m_errorString;
 }
 
 AuditLogEntry DecryptVerifyResult::auditLog() const
 {
     return d->m_auditLog;
 }
 
 QPointer<Task> DecryptVerifyResult::parentTask() const
 {
     return d->m_parentTask;
 }
 
 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;
     QPointer<QGpgME::Job> job;
     bool isNotepad = false;
 };
 
 AbstractDecryptVerifyTask::AbstractDecryptVerifyTask(QObject *parent)
     : Task(parent)
     , d(new Private)
 {
 }
 
 AbstractDecryptVerifyTask::~AbstractDecryptVerifyTask()
 {
 }
 
 void AbstractDecryptVerifyTask::cancel()
 {
     qCDebug(KLEOPATRA_LOG) << this << __func__;
     if (d->job) {
         d->job->slotCancel();
     }
 }
 
 Mailbox AbstractDecryptVerifyTask::informativeSender() const
 {
     return d->informativeSender;
 }
 
 void AbstractDecryptVerifyTask::setInformativeSender(const Mailbox &sender)
 {
     d->informativeSender = sender;
 }
 
 QGpgME::Job *AbstractDecryptVerifyTask::job() const
 {
     return d->job;
 }
 
 void AbstractDecryptVerifyTask::setJob(QGpgME::Job *job)
 {
     d->job = job;
 }
 
 class DecryptVerifyTask::Private
 {
     DecryptVerifyTask *const q;
 
 public:
     explicit Private(DecryptVerifyTask *qq)
         : q{qq}
     {
     }
 
     void startDecryptVerifyJob();
     void startDecryptVerifyArchiveJob();
 
     void slotResult(const DecryptionResult &, const VerificationResult &, const QByteArray & = {});
 
     std::shared_ptr<Input> m_input;
     std::shared_ptr<Output> m_output;
     const QGpgME::Protocol *m_backend = nullptr;
     Protocol m_protocol = UnknownProtocol;
     bool m_ignoreMDCError = false;
     bool m_extractArchive = false;
     QString m_inputFilePath;
     QString m_outputFilePath;
     QString m_outputDirectory;
 };
 
 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 AuditLogEntry auditLog = auditLogFromSender(q->sender());
     if (m_output) {
         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) {
                 q->emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
                 return;
             } catch (const std::exception &e) {
                 q->emitResult(
                     q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
                 return;
             } catch (...) {
                 q->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 ? m_output->errorString() : QString{};
     if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) || (m_output && m_output->failed())) {
         q->emitResult(q->fromDecryptResult(drErr ? dr.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog));
         return;
     }
 
     q->emitResult(q->fromDecryptVerifyResult(dr, vr, plainText, m_output ? m_output->fileName() : m_outputFilePath, auditLog));
 }
 
 DecryptVerifyTask::DecryptVerifyTask(QObject *parent)
     : AbstractDecryptVerifyTask(parent)
     , d(new Private(this))
 {
 }
 
 DecryptVerifyTask::~DecryptVerifyTask()
 {
 }
 
 void DecryptVerifyTask::setInput(const std::shared_ptr<Input> &input)
 {
     d->m_input = input;
     kleo_assert(d->m_input && d->m_input->ioDevice());
 }
 
 void DecryptVerifyTask::setOutput(const std::shared_ptr<Output> &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...", inputLabel());
 }
 
 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() : QFileInfo{d->m_inputFilePath}.fileName();
 }
 
 QString DecryptVerifyTask::outputLabel() const
 {
     if (d->m_output) {
         return d->m_output->label();
     } else if (!d->m_outputFilePath.isEmpty()) {
         return QFileInfo{d->m_outputFilePath}.fileName();
     } else {
         return d->m_outputDirectory;
     }
 }
 
 Protocol DecryptVerifyTask::protocol() const
 {
     return d->m_protocol;
 }
 
 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::setExtractArchive(bool extract)
 {
     d->m_extractArchive = extract;
 }
 
 void DecryptVerifyTask::setInputFile(const QString &path)
 {
     d->m_inputFilePath = path;
 }
 
 void DecryptVerifyTask::setOutputFile(const QString &path)
 {
     d->m_outputFilePath = path;
 }
 
 void DecryptVerifyTask::setOutputDirectory(const QString &directory)
 {
     d->m_outputDirectory = directory;
 }
 
 static bool archiveJobsCanBeUsed(GpgME::Protocol protocol)
 {
     return (protocol == GpgME::OpenPGP) && QGpgME::DecryptVerifyArchiveJob::isSupported();
 }
 
 void DecryptVerifyTask::doStart()
 {
     kleo_assert(d->m_backend);
     if (d->m_extractArchive && archiveJobsCanBeUsed(d->m_protocol)) {
         d->startDecryptVerifyArchiveJob();
     } else {
         d->startDecryptVerifyJob();
     }
 }
 
 static void setIgnoreMDCErrorFlag(QGpgME::Job *job, bool ignoreMDCError)
 {
     if (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" << Formatting::errorAsString(err);
             }
         }
     }
 }
 
 void DecryptVerifyTask::Private::startDecryptVerifyJob()
 {
 #if QGPGME_FILE_JOBS_SUPPORT_DIRECT_FILE_IO
     if (!m_outputFilePath.isEmpty() && QFile::exists(m_outputFilePath)) {
         // The output files are always written to a temporary location. Therefore, this can only occur
         // if two signed/encrypted files with the same name in different folders are verified/decrypted
         // because they would be written to the same temporary location.
         QMetaObject::invokeMethod(
             q,
             [this]() {
                 slotResult(DecryptionResult{Error::fromCode(GPG_ERR_EEXIST)}, VerificationResult{});
             },
             Qt::QueuedConnection);
         return;
     }
 #endif
     try {
         std::unique_ptr<QGpgME::DecryptVerifyJob> job{m_backend->decryptVerifyJob()};
         kleo_assert(job);
         setIgnoreMDCErrorFlag(job.get(), m_ignoreMDCError);
         QObject::connect(job.get(),
                          &QGpgME::DecryptVerifyJob::result,
                          q,
                          [this](const GpgME::DecryptionResult &decryptResult, const GpgME::VerificationResult &verifyResult, const QByteArray &plainText) {
                              slotResult(decryptResult, verifyResult, plainText);
                          });
         connect(job.get(), &QGpgME::Job::jobProgress, q, &DecryptVerifyTask::setProgress);
 #if QGPGME_SUPPORTS_PROCESS_ALL_SIGNATURES
         job->setProcessAllSignatures(true);
 #endif
 #if QGPGME_FILE_JOBS_SUPPORT_DIRECT_FILE_IO
         if (!m_inputFilePath.isEmpty() && !m_outputFilePath.isEmpty()) {
             job->setInputFile(m_inputFilePath);
             job->setOutputFile(m_outputFilePath);
             const auto err = job->startIt();
         } else {
             ensureIOOpen(m_input->ioDevice().get(), m_output->ioDevice().get());
             job->start(m_input->ioDevice(), m_output->ioDevice());
         }
 #else
         ensureIOOpen(m_input->ioDevice().get(), m_output->ioDevice().get());
         job->start(m_input->ioDevice(), m_output->ioDevice());
 #endif
         q->setJob(job.release());
     } catch (const GpgME::Exception &e) {
         q->emitResult(q->fromDecryptVerifyResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLogEntry()));
     } catch (const std::exception &e) {
         q->emitResult(
             q->fromDecryptVerifyResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLogEntry()));
     } catch (...) {
         q->emitResult(q->fromDecryptVerifyResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLogEntry()));
     }
 }
 
 void DecryptVerifyTask::Private::startDecryptVerifyArchiveJob()
 {
     std::unique_ptr<QGpgME::DecryptVerifyArchiveJob> job{m_backend->decryptVerifyArchiveJob()};
     kleo_assert(job);
     setIgnoreMDCErrorFlag(job.get(), m_ignoreMDCError);
     connect(job.get(),
             &QGpgME::DecryptVerifyArchiveJob::result,
             q,
             [this](const GpgME::DecryptionResult &decryptResult, const GpgME::VerificationResult &verifyResult) {
                 slotResult(decryptResult, verifyResult);
             });
     connect(job.get(), &QGpgME::Job::jobProgress, q, &DecryptVerifyTask::setProgress);
     // make sure that we don't use an existing output directory
     const auto outputDirectory = ensureUniqueDirectory(m_outputDirectory);
     if (outputDirectory.isEmpty()) {
         q->emitResult(q->fromDecryptVerifyResult(Error::fromCode(GPG_ERR_GENERAL), {}, {}));
         return;
     }
     m_outputDirectory = outputDirectory;
     m_outputFilePath = outputDirectory;
 #if QGPGME_SUPPORTS_PROCESS_ALL_SIGNATURES
     job->setProcessAllSignatures(true);
 #endif
     job->setInputFile(m_inputFilePath);
     job->setOutputDirectory(m_outputDirectory);
     const auto err = job->startIt();
     q->setJob(job.release());
     if (err) {
         q->emitResult(q->fromDecryptVerifyResult(err, {}, {}));
     }
 }
 
 class DecryptTask::Private
 {
     DecryptTask *const q;
 
 public:
     explicit Private(DecryptTask *qq)
         : q{qq}
     {
     }
 
     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, &QGpgME::Job::jobProgress, q, &DecryptTask::setProgress);
     }
 
     std::shared_ptr<Input> m_input;
     std::shared_ptr<Output> m_output;
     const QGpgME::Protocol *m_backend = nullptr;
     Protocol m_protocol = UnknownProtocol;
 };
 
 void DecryptTask::Private::slotResult(const DecryptionResult &result, const QByteArray &plainText)
 {
     {
         std::stringstream ss;
         ss << result;
         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
     }
     const AuditLogEntry 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) {
             q->emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
             return;
         } catch (const std::exception &e) {
             q->emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
             return;
         } catch (...) {
             q->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()) {
         q->emitResult(q->fromDecryptResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog));
         return;
     }
 
     q->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> &input)
 {
     d->m_input = input;
     kleo_assert(d->m_input && d->m_input->ioDevice());
 }
 
 void DecryptTask::setOutput(const std::shared_ptr<Output> &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::doStart()
 {
     kleo_assert(d->m_backend);
 
     try {
         std::unique_ptr<QGpgME::DecryptJob> job{d->m_backend->decryptJob()};
         kleo_assert(job);
         d->registerJob(job.get());
         ensureIOOpen(d->m_input->ioDevice().get(), d->m_output->ioDevice().get());
         job->start(d->m_input->ioDevice(), d->m_output->ioDevice());
         setJob(job.release());
     } catch (const GpgME::Exception &e) {
         emitResult(fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLogEntry()));
     } catch (const std::exception &e) {
         emitResult(fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLogEntry()));
     } catch (...) {
         emitResult(fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLogEntry()));
     }
 }
 
 class VerifyOpaqueTask::Private
 {
     VerifyOpaqueTask *const q;
 
 public:
     explicit Private(VerifyOpaqueTask *qq)
         : q{qq}
     {
     }
 
     void startVerifyOpaqueJob();
     void startDecryptVerifyArchiveJob();
 
     void slotResult(const VerificationResult &, const QByteArray & = {});
 
     std::shared_ptr<Input> m_input;
     std::shared_ptr<Output> m_output;
     const QGpgME::Protocol *m_backend = nullptr;
     Protocol m_protocol = UnknownProtocol;
     bool m_extractArchive = false;
     QString m_inputFilePath;
     QString m_outputFilePath;
     QString m_outputDirectory;
 };
 
 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 AuditLogEntry auditLog = auditLogFromSender(q->sender());
     if (m_output) {
         if (result.error().code()) {
             m_output->cancel();
         } else {
             try {
                 kleo_assert(!result.isNull());
                 m_output->finalize();
             } catch (const GpgME::Exception &e) {
                 q->emitResult(q->fromVerifyOpaqueResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
                 return;
             } catch (const std::exception &e) {
                 q->emitResult(
                     q->fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
                 return;
             } catch (...) {
                 q->emitResult(q->fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
                 return;
             }
         }
     }
 
     const int drErr = result.error().code();
     const QString errorString = m_output ? m_output->errorString() : QString{};
     if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) || (m_output && m_output->failed())) {
         q->emitResult(q->fromVerifyOpaqueResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO), errorString, auditLog));
         return;
     }
 
     q->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> &input)
 {
     d->m_input = input;
     kleo_assert(d->m_input && d->m_input->ioDevice());
 }
 
 void VerifyOpaqueTask::setOutput(const std::shared_ptr<Output> &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...", inputLabel());
 }
 
 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() : QFileInfo{d->m_inputFilePath}.fileName();
 }
 
 QString VerifyOpaqueTask::outputLabel() const
 {
     if (d->m_output) {
         return d->m_output->label();
     } else if (!d->m_outputFilePath.isEmpty()) {
         return QFileInfo{d->m_outputFilePath}.fileName();
     } else {
         return d->m_outputDirectory;
     }
 }
 
 Protocol VerifyOpaqueTask::protocol() const
 {
     return d->m_protocol;
 }
 
 void VerifyOpaqueTask::setExtractArchive(bool extract)
 {
     d->m_extractArchive = extract;
 }
 
 void VerifyOpaqueTask::setInputFile(const QString &path)
 {
     d->m_inputFilePath = path;
 }
 
 void VerifyOpaqueTask::setOutputFile(const QString &path)
 {
     d->m_outputFilePath = path;
 }
 
 void VerifyOpaqueTask::setOutputDirectory(const QString &directory)
 {
     d->m_outputDirectory = directory;
 }
 
 void VerifyOpaqueTask::doStart()
 {
     kleo_assert(d->m_backend);
     if (d->m_extractArchive && archiveJobsCanBeUsed(d->m_protocol)) {
         d->startDecryptVerifyArchiveJob();
     } else {
         d->startVerifyOpaqueJob();
     }
 }
 
 void VerifyOpaqueTask::Private::startVerifyOpaqueJob()
 {
 #if QGPGME_FILE_JOBS_SUPPORT_DIRECT_FILE_IO
     if (!m_outputFilePath.isEmpty() && QFile::exists(m_outputFilePath)) {
         // The output files are always written to a temporary location. Therefore, this can only occur
         // if two signed/encrypted files with the same name in different folders are verified/decrypted
         // because they would be written to the same temporary location.
         QMetaObject::invokeMethod(
             q,
             [this]() {
                 slotResult(VerificationResult{Error::fromCode(GPG_ERR_EEXIST)});
             },
             Qt::QueuedConnection);
         return;
     }
 #endif
     try {
         std::unique_ptr<QGpgME::VerifyOpaqueJob> job{m_backend->verifyOpaqueJob()};
         kleo_assert(job);
         connect(job.get(), &QGpgME::VerifyOpaqueJob::result, q, [this](const GpgME::VerificationResult &result, const QByteArray &plainText) {
             slotResult(result, plainText);
         });
         connect(job.get(), &QGpgME::Job::jobProgress, q, &VerifyOpaqueTask::setProgress);
 #if QGPGME_SUPPORTS_PROCESS_ALL_SIGNATURES
         job->setProcessAllSignatures(true);
 #endif
 #if QGPGME_FILE_JOBS_SUPPORT_DIRECT_FILE_IO
         if (!m_inputFilePath.isEmpty() && !m_outputFilePath.isEmpty()) {
             job->setInputFile(m_inputFilePath);
             job->setOutputFile(m_outputFilePath);
             const auto err = job->startIt();
         } else {
             ensureIOOpen(m_input->ioDevice().get(), m_output ? m_output->ioDevice().get() : nullptr);
             job->start(m_input->ioDevice(), m_output ? m_output->ioDevice() : std::shared_ptr<QIODevice>());
         }
 #else
         ensureIOOpen(m_input->ioDevice().get(), m_output ? m_output->ioDevice().get() : nullptr);
         job->start(m_input->ioDevice(), m_output ? m_output->ioDevice() : std::shared_ptr<QIODevice>());
 #endif
         q->setJob(job.release());
     } catch (const GpgME::Exception &e) {
         q->emitResult(q->fromVerifyOpaqueResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLogEntry()));
     } catch (const std::exception &e) {
         q->emitResult(
             q->fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLogEntry()));
     } catch (...) {
         q->emitResult(q->fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLogEntry()));
     }
 }
 
 void VerifyOpaqueTask::Private::startDecryptVerifyArchiveJob()
 {
     std::unique_ptr<QGpgME::DecryptVerifyArchiveJob> job{m_backend->decryptVerifyArchiveJob()};
     kleo_assert(job);
     connect(job.get(), &QGpgME::DecryptVerifyArchiveJob::result, q, [this](const DecryptionResult &, const VerificationResult &verifyResult) {
         slotResult(verifyResult);
     });
     connect(job.get(), &QGpgME::DecryptVerifyArchiveJob::dataProgress, q, &VerifyOpaqueTask::setProgress);
     // make sure that we don't use an existing output directory
     const auto outputDirectory = ensureUniqueDirectory(m_outputDirectory);
     if (outputDirectory.isEmpty()) {
         q->emitResult(q->fromDecryptVerifyResult(Error::fromCode(GPG_ERR_GENERAL), {}, {}));
         return;
     }
     m_outputFilePath = outputDirectory;
     m_outputDirectory = outputDirectory;
 #if QGPGME_SUPPORTS_PROCESS_ALL_SIGNATURES
     job->setProcessAllSignatures(true);
 #endif
     job->setInputFile(m_inputFilePath);
     job->setOutputDirectory(m_outputDirectory);
     const auto err = job->startIt();
     q->setJob(job.release());
     if (err) {
         q->emitResult(q->fromVerifyOpaqueResult(err, {}, {}));
     }
 }
 
 class VerifyDetachedTask::Private
 {
     VerifyDetachedTask *const q;
 
 public:
     explicit Private(VerifyDetachedTask *qq)
         : q{qq}
     {
     }
 
     void slotResult(const VerificationResult &);
 
     void registerJob(QGpgME::VerifyDetachedJob *job)
     {
         q->connect(job, SIGNAL(result(GpgME::VerificationResult)), q, SLOT(slotResult(GpgME::VerificationResult)));
         q->connect(job, &QGpgME::Job::jobProgress, q, &VerifyDetachedTask::setProgress);
     }
 
     QString signatureLabel() const;
     QString signedDataLabel() const;
 
     std::shared_ptr<Input> m_input, m_signedData;
     const QGpgME::Protocol *m_backend = nullptr;
     Protocol m_protocol = UnknownProtocol;
     QString m_signatureFilePath;
     QString m_signedFilePath;
 };
 
 void VerifyDetachedTask::Private::slotResult(const VerificationResult &result)
 {
     updateKeys(result);
     {
         std::stringstream ss;
         ss << result;
         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
     }
     const AuditLogEntry auditLog = auditLogFromSender(q->sender());
     try {
         kleo_assert(!result.isNull());
         q->emitResult(q->fromVerifyDetachedResult(result, auditLog));
     } catch (const GpgME::Exception &e) {
         q->emitResult(q->fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
     } catch (const std::exception &e) {
         q->emitResult(q->fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
     } catch (...) {
         q->emitResult(q->fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
     }
 }
 
 QString VerifyDetachedTask::Private::signatureLabel() const
 {
     return m_input ? m_input->label() : m_signatureFilePath;
 }
 
 QString VerifyDetachedTask::Private::signedDataLabel() const
 {
     return m_signedData ? m_signedData->label() : m_signedFilePath;
 }
 
 VerifyDetachedTask::VerifyDetachedTask(QObject *parent)
     : AbstractDecryptVerifyTask(parent)
     , d(new Private(this))
 {
 }
 
 VerifyDetachedTask::~VerifyDetachedTask()
 {
 }
 
 void VerifyDetachedTask::setInput(const std::shared_ptr<Input> &input)
 {
     d->m_input = input;
     kleo_assert(d->m_input && d->m_input->ioDevice());
 }
 
 void VerifyDetachedTask::setSignedData(const std::shared_ptr<Input> &signedData)
 {
     d->m_signedData = signedData;
     kleo_assert(d->m_signedData && d->m_signedData->ioDevice());
 }
 
 void VerifyDetachedTask::setSignatureFile(const QString &path)
 {
     d->m_signatureFilePath = path;
 }
 
 void VerifyDetachedTask::setSignedFile(const QString &path)
 {
     d->m_signedFilePath = path;
 }
 
 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
 {
     const QString signedDataLabel = d->signedDataLabel();
     if (!signedDataLabel.isEmpty()) {
         return xi18nc(
             "Verification of a detached signature in progress. The first file contains the data."
             "The second file is the signature file.",
             "Verifying <filename>%1</filename> with <filename>%2</filename>...",
             signedDataLabel,
             d->signatureLabel());
     }
     return i18n("Verifying signature %1...", d->signatureLabel());
 }
 
 QString VerifyDetachedTask::inputLabel() const
 {
     return d->signatureLabel();
 }
 
 QString VerifyDetachedTask::outputLabel() const
 {
     return d->signedDataLabel();
 }
 
 Protocol VerifyDetachedTask::protocol() const
 {
     return d->m_protocol;
 }
 
 void VerifyDetachedTask::doStart()
 {
     kleo_assert(d->m_backend);
     try {
         std::unique_ptr<QGpgME::VerifyDetachedJob> job{d->m_backend->verifyDetachedJob()};
         kleo_assert(job);
         d->registerJob(job.get());
 #if QGPGME_SUPPORTS_PROCESS_ALL_SIGNATURES
         job->setProcessAllSignatures(true);
 #endif
 #if QGPGME_FILE_JOBS_SUPPORT_DIRECT_FILE_IO
         if (d->m_protocol == GpgME::OpenPGP && !d->m_signatureFilePath.isEmpty() && !d->m_signedFilePath.isEmpty()) {
             job->setSignatureFile(d->m_signatureFilePath);
             job->setSignedFile(d->m_signedFilePath);
             job->startIt();
         } else {
             ensureIOOpen(d->m_input->ioDevice().get(), nullptr);
             ensureIOOpen(d->m_signedData->ioDevice().get(), nullptr);
             job->start(d->m_input->ioDevice(), d->m_signedData->ioDevice());
         }
 #else
         ensureIOOpen(d->m_input->ioDevice().get(), nullptr);
         ensureIOOpen(d->m_signedData->ioDevice().get(), nullptr);
         job->start(d->m_input->ioDevice(), d->m_signedData->ioDevice());
 #endif
         setJob(job.release());
     } catch (const GpgME::Exception &e) {
         emitResult(fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLogEntry()));
     } catch (const std::exception &e) {
         emitResult(
             fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLogEntry()));
     } catch (...) {
         emitResult(fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLogEntry()));
     }
 }
 
 void AbstractDecryptVerifyTask::setIsNotepad(bool isNotepad)
 {
     d->isNotepad = isNotepad;
 }
 
 bool AbstractDecryptVerifyTask::isNotepad() const
 {
     return d->isNotepad;
 }
 
 #include "moc_decryptverifytask.cpp"