diff --git a/autotests/kuniqueservicetest.cpp b/autotests/kuniqueservicetest.cpp index 8ffbb50b7..42044cad6 100644 --- a/autotests/kuniqueservicetest.cpp +++ b/autotests/kuniqueservicetest.cpp @@ -1,169 +1,169 @@ /* This file is part of Kleopatra SPDX-FileCopyrightText: 2016 Intevation GmbH It is based on libkdbus kdbusservicetest which is: SPDX-FileCopyrightText: 1999 Waldo Bastian SPDX-FileCopyrightText: 2011 David Faure SPDX-FileCopyrightText: 2011 Kevin Ottens SPDX-License-Identifier: LGPL-2.0-only */ /* The main modification in this test is that every activateRequested * call needs to set the exit code to signal the application it's done. */ #include #include #include #include #include #include #include #include "utils/kuniqueservice.h" #include #include using namespace std::chrono_literals; class TestObject : public QObject { Q_OBJECT public: TestObject(KUniqueService *service) : m_proc(nullptr), m_callCount(0), m_service(service) {} - ~TestObject() + ~TestObject() override { if (m_proc) { m_proc->waitForFinished(); } } int callCount() const { return m_callCount; } private Q_SLOTS: void slotActivateRequested(const QStringList &args, const QString &workingDirectory) { Q_UNUSED(workingDirectory) qDebug() << "Application executed with args" << args; ++m_callCount; if (m_callCount == 1) { Q_ASSERT(args.count() == 1); Q_ASSERT(args.at(0) == QLatin1String("dummy call")); m_service->setExitValue(0); } else if (m_callCount == 2) { Q_ASSERT(args.count() == 2); Q_ASSERT(args.at(1) == QLatin1String("bad call")); m_service->setExitValue(4); } else if (m_callCount == 3) { Q_ASSERT(args.count() == 3); Q_ASSERT(args.at(1) == QLatin1String("real call")); Q_ASSERT(args.at(2) == QLatin1String("second arg")); m_service->setExitValue(0); // OK, all done, quit QCoreApplication::instance()->quit(); } } void slotProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitStatus) qDebug() << "Process exited with code" << exitCode; m_proc = nullptr; if (m_callCount == 2) { Q_ASSERT(exitCode == 4); secondCall(); } } void firstCall() { QStringList args; args << QStringLiteral("bad call"); executeNewChild(args); } void secondCall() { QStringList args; args << QStringLiteral("real call") << QStringLiteral("second arg"); executeNewChild(args); } private: void executeNewChild(const QStringList &args) { // Duplicated from kglobalsettingstest.cpp - make a shared helper method? m_proc = new QProcess(this); connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); QString appName = QStringLiteral("kuniqueservicetest"); #ifdef Q_OS_WIN appName += QStringLiteral(".exe"); #else if (QFile::exists(appName + QStringLiteral(".shell"))) { appName = QStringLiteral("./") + appName + QStringLiteral(".shell"); } else if (QFile::exists(QCoreApplication::applicationFilePath())) { appName = QCoreApplication::applicationFilePath(); } else { Q_ASSERT(QFile::exists(appName)); appName = QStringLiteral("./") + appName; } #endif qDebug() << "about to run" << appName << args; m_proc->start(appName, args); } QProcess *m_proc; int m_callCount; KUniqueService *m_service; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QCoreApplication::setApplicationName(QStringLiteral("kuniqueservicetest")); QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); KUniqueService service; TestObject testObject(&service); QObject::connect(&service, SIGNAL(activateRequested(QStringList,QString)), &testObject, SLOT(slotActivateRequested(QStringList,QString))); // Testcase for the problem coming from the old fork-on-startup solution: // the "Activate" D-Bus call would time out if the app took too much time // to be ready. //printf("Sleeping.\n"); //sleep(200); QStringList args; args << QStringLiteral("dummy call"); QMetaObject::invokeMethod(&service, "activateRequested", Qt::QueuedConnection, Q_ARG(QStringList, args), Q_ARG(QString, QDir::currentPath())); QTimer::singleShot(400ms, &testObject, SLOT(firstCall())); qDebug() << "Running."; a.exec(); qDebug() << "Terminating."; Q_ASSERT(testObject.callCount() == 3); const bool ok = testObject.callCount() == 3; return ok ? 0 : 1; } #include "kuniqueservicetest.moc" diff --git a/src/commands/adduseridcommand.cpp b/src/commands/adduseridcommand.cpp index 1afd5e349..907d15eae 100644 --- a/src/commands/adduseridcommand.cpp +++ b/src/commands/adduseridcommand.cpp @@ -1,272 +1,272 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/adduseridcommand.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 "adduseridcommand.h" #include "command_p.h" #include "dialogs/adduseriddialog.h" #include "dialogs/addemaildialog.h" #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace GpgME; class AddUserIDCommand::Private : public Command::Private { friend class ::Kleo::Commands::AddUserIDCommand; AddUserIDCommand *q_func() const { return static_cast(q); } public: explicit Private(AddUserIDCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotDialogAccepted(); void slotSimpleDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void ensureDialogCreated(); void createJob(); void showErrorDialog(const Error &error); void showSuccessDialog(); private: GpgME::Key key; QPointer dialog; QPointer simpleDialog; QPointer job; }; AddUserIDCommand::Private *AddUserIDCommand::d_func() { return static_cast(d.get()); } const AddUserIDCommand::Private *AddUserIDCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() AddUserIDCommand::Private::Private(AddUserIDCommand *qq, KeyListController *c) : Command::Private(qq, c), key(), dialog(), job() { } AddUserIDCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); if (dialog) { delete dialog; } if (simpleDialog) { delete simpleDialog; } } AddUserIDCommand::AddUserIDCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } AddUserIDCommand::AddUserIDCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } AddUserIDCommand::AddUserIDCommand(const GpgME::Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } void AddUserIDCommand::Private::init() { } AddUserIDCommand::~AddUserIDCommand() { qCDebug(KLEOPATRA_LOG); } void AddUserIDCommand::doStart() { const std::vector keys = d->keys(); if (keys.size() != 1 || keys.front().protocol() != GpgME::OpenPGP || !keys.front().hasSecret()) { d->finished(); return; } d->key = keys.front(); d->ensureDialogCreated(); Q_ASSERT(d->dialog); const UserID uid = d->key.userID(0); // d->simpleDialog->setEmail(Formatting::prettyEMail(uid.email(), uid.id())); d->dialog->setName(QString::fromUtf8(uid.name())); d->dialog->setEmail(Formatting::prettyEMail(uid.email(), uid.id())); d->dialog->setComment(QString::fromUtf8(uid.comment())); d->simpleDialog->show(); } void AddUserIDCommand::Private::slotSimpleDialogAccepted() { if (simpleDialog->advancedSelected()) { qDebug() << "thinking advanced selected"; dialog->show(); return; } createJob(); if (!job) { finished(); return; } if (const Error err = job->start(key, QString(), simpleDialog->email(), QString())) { showErrorDialog(err); finished(); } } void AddUserIDCommand::Private::slotDialogAccepted() { Q_ASSERT(dialog); createJob(); if (!job) { finished(); } else if (const Error err = job->start(key, dialog->name(), dialog->email(), dialog->comment())) { showErrorDialog(err); finished(); } } void AddUserIDCommand::Private::slotDialogRejected() { Q_EMIT q->canceled(); finished(); } void AddUserIDCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) ; else if (err) { showErrorDialog(err); } else { showSuccessDialog(); } finished(); } void AddUserIDCommand::doCancel() { qCDebug(KLEOPATRA_LOG); if (d->job) { d->job->slotCancel(); } } void AddUserIDCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new AddUserIDDialog; applyWindowID(dialog); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); simpleDialog = new AddEmailDialog; applyWindowID(simpleDialog); connect(simpleDialog, SIGNAL(accepted()), q, SLOT(slotSimpleDialogAccepted())); connect(simpleDialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void AddUserIDCommand::Private::createJob() { Q_ASSERT(!job); const auto backend = (key.protocol() == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); if (!backend) { return; } QGpgME::AddUserIDJob *const j = backend->addUserIDJob(); if (!j) { return; } connect(j, &QGpgME::Job::progress, q, &Command::progress); connect(j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); job = j; } void AddUserIDCommand::Private::showErrorDialog(const Error &err) { error(xi18nc("@info", "An error occurred while trying to add the user-id: " "%1", QString::fromLocal8Bit(err.asString())), i18nc("@title:window", "Add User-ID Error")); } void AddUserIDCommand::Private::showSuccessDialog() { information(i18nc("@info", "User-ID successfully added."), i18nc("@title:window", "Add User-ID Succeeded")); } #undef d #undef q #include "moc_adduseridcommand.cpp" diff --git a/src/commands/authenticatepivcardapplicationcommand.cpp b/src/commands/authenticatepivcardapplicationcommand.cpp index abab34757..4fcb5283a 100644 --- a/src/commands/authenticatepivcardapplicationcommand.cpp +++ b/src/commands/authenticatepivcardapplicationcommand.cpp @@ -1,192 +1,192 @@ /* commands/authenticatepivcardapplicationcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "authenticatepivcardapplicationcommand.h" #include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h" #include #include #include #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36 # define GPG_ERROR_HAS_BAD_AUTH #endif #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class AuthenticatePIVCardApplicationCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::AuthenticatePIVCardApplicationCommand; AuthenticatePIVCardApplicationCommand *q_func() const { return static_cast(q); } public: explicit Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p); - ~Private(); + ~Private() override; void init(); private: void slotResult(const Error &err); void slotDialogAccepted(); void slotDialogRejected(); private: void authenticate(const QByteArray& adminKey); void retryAskingForKey(); void ensureDialogCreated(); private: QString prompt; QPointer dialog; }; AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() { return static_cast(d.get()); } const AuthenticatePIVCardApplicationCommand::Private *AuthenticatePIVCardApplicationCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() AuthenticatePIVCardApplicationCommand::Private::Private(AuthenticatePIVCardApplicationCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , dialog() { } AuthenticatePIVCardApplicationCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::Private::~Private()"; } AuthenticatePIVCardApplicationCommand::AuthenticatePIVCardApplicationCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void AuthenticatePIVCardApplicationCommand::Private::init() { } AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand() { qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::~AuthenticatePIVCardApplicationCommand()"; } void AuthenticatePIVCardApplicationCommand::setPrompt(const QString& prompt) { d->prompt = prompt; } void AuthenticatePIVCardApplicationCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::doStart()"; // at first, try to authenticate using the default application administration key d->authenticate(QByteArray::fromHex("010203040506070801020304050607080102030405060708")); } void AuthenticatePIVCardApplicationCommand::doCancel() { } void AuthenticatePIVCardApplicationCommand::Private::authenticate(const QByteArray& adminKey) { qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::authenticate()"; const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const QByteArray plusPercentEncodedAdminKey = adminKey.toPercentEncoding().replace(' ', '+'); const QByteArray command = QByteArray("SCD SETATTR AUTH-ADM-KEY ") + plusPercentEncodedAdminKey; ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, "slotResult"); } void AuthenticatePIVCardApplicationCommand::Private::slotResult(const Error &err) { qCDebug(KLEOPATRA_LOG) << "AuthenticatePIVCardApplicationCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err.isCanceled()) { canceled(); return; } if (err) { #ifdef GPG_ERROR_HAS_BAD_AUTH if (err.code() == GPG_ERR_BAD_AUTH) { retryAskingForKey(); return; } #endif error(i18nc("@info", "Authenticating to the card failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } finished(); } void AuthenticatePIVCardApplicationCommand::Private::retryAskingForKey() { ensureDialogCreated(); Q_ASSERT(dialog); dialog->show(); } void AuthenticatePIVCardApplicationCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setLabelText(prompt.isEmpty() ? i18n("Please enter the PIV Card Application Administration Key in hex-encoded form.") : prompt); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void AuthenticatePIVCardApplicationCommand::Private::slotDialogAccepted() { authenticate(dialog->adminKey()); } void AuthenticatePIVCardApplicationCommand::Private::slotDialogRejected() { canceled(); } #undef d #undef q #include "moc_authenticatepivcardapplicationcommand.cpp" diff --git a/src/commands/cardcommand_p.h b/src/commands/cardcommand_p.h index 911aeabc5..58b9b11af 100644 --- a/src/commands/cardcommand_p.h +++ b/src/commands/cardcommand_p.h @@ -1,41 +1,41 @@ /* commands/cardcommand_p.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "cardcommand.h" #include "command_p.h" class Kleo::CardCommand::Private : public Command::Private { friend class ::Kleo::CardCommand; Kleo::CardCommand *q_func() const { return static_cast(q); } public: explicit Private(CardCommand *qq, const std::string &serialNumber, QWidget *parent); - ~Private(); + ~Private() override; std::string serialNumber() const { return serialNumber_; } protected: void setSerialNumber(const std::string &serialNumber) { serialNumber_ = serialNumber; } private: std::string serialNumber_; }; diff --git a/src/commands/certificatetopivcardcommand.cpp b/src/commands/certificatetopivcardcommand.cpp index cc7a23fe0..70fed3406 100644 --- a/src/commands/certificatetopivcardcommand.cpp +++ b/src/commands/certificatetopivcardcommand.cpp @@ -1,257 +1,257 @@ /* commands/certificatetopivcardcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "certificatetopivcardcommand.h" #include "cardcommand_p.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "utils/writecertassuantransaction.h" #include #include #include #include #include #include #include #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36 # define GPG_ERROR_HAS_NO_AUTH #endif #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; class CertificateToPIVCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::CertificateToPIVCardCommand; CertificateToPIVCardCommand *q_func() const { return static_cast(q); } public: explicit Private(CertificateToPIVCardCommand *qq, const std::string &slot, const std::string &serialno); - ~Private(); + ~Private() override; private: void start(); void startCertificateToPIVCard(); void authenticate(); void authenticationFinished(); void authenticationCanceled(); private: std::string cardSlot; Key certificate; bool hasBeenCanceled = false; }; CertificateToPIVCardCommand::Private *CertificateToPIVCardCommand::d_func() { return static_cast(d.get()); } const CertificateToPIVCardCommand::Private *CertificateToPIVCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() CertificateToPIVCardCommand::Private::Private(CertificateToPIVCardCommand *qq, const std::string &slot, const std::string &serialno) : CardCommand::Private(qq, serialno, nullptr) , cardSlot(slot) { } CertificateToPIVCardCommand::Private::~Private() { } namespace { static Key getCertificateToWriteToPIVCard(const std::string &cardSlot, const std::shared_ptr &card) { if (!cardSlot.empty()) { const std::string cardKeygrip = card->keyInfo(cardSlot).grip; const auto certificate = KeyCache::instance()->findSubkeyByKeyGrip(cardKeygrip).parent(); if (certificate.isNull() || certificate.protocol() != GpgME::CMS) { return Key(); } if ((cardSlot == PIVCard::pivAuthenticationKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::cardAuthenticationKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::digitalSignatureKeyRef() && certificate.canSign()) || (cardSlot == PIVCard::keyManagementKeyRef() && certificate.canEncrypt())) { return certificate; } } return Key(); } } void CertificateToPIVCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::Private::start()"; const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } certificate = getCertificateToWriteToPIVCard(cardSlot, pivCard); if (certificate.isNull()) { error(i18n("Sorry! No suitable certificate to write to this card slot was found.")); finished(); return; } const QString certificateInfo = i18nc("X.509 certificate DN (validity, created: date)", "%1 (%2, created: %3)", DN(certificate.userID(0).id()).prettyDN(), Formatting::complianceStringShort(certificate), Formatting::creationDateString(certificate)); const QString message = i18nc( "@info %1 name of card slot, %2 serial number of card", "

Please confirm that you want to write the following certificate to the %1 slot of card %2:

" "
%3
", PIVCard::keyDisplayName(cardSlot), QString::fromStdString(serialNumber()), certificateInfo); auto confirmButton = KStandardGuiItem::yes(); confirmButton.setText(i18nc("@action:button", "Write certificate")); confirmButton.setToolTip(QString()); const auto choice = KMessageBox::questionYesNo( parentWidgetOrView(), message, i18nc("@title:window", "Write certificate to card"), confirmButton, KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::WindowModal); if (choice != KMessageBox::Yes) { finished(); return; } startCertificateToPIVCard(); } void CertificateToPIVCardCommand::Private::startCertificateToPIVCard() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::Private::startCertificateToPIVCard()"; auto ctx = Context::createForProtocol(GpgME::CMS); QGpgME::QByteArrayDataProvider dp; Data data(&dp); const Error err = ctx->exportPublicKeys(certificate.primaryFingerprint(), data); if (err) { error(i18nc("@info", "Exporting the certificate failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); finished(); return; } const QByteArray certificateData = dp.data(); const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const QByteArray command = QByteArrayLiteral("SCD WRITECERT ") + QByteArray::fromStdString(cardSlot); auto transaction = std::unique_ptr(new WriteCertAssuanTransaction(certificateData)); ReaderStatus::mutableInstance()->startTransaction(pivCard, command, q_func(), "certificateToPIVCardDone", std::move(transaction)); } void CertificateToPIVCardCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticate()"; auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void CertificateToPIVCardCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticationFinished()"; if (!hasBeenCanceled) { startCertificateToPIVCard(); } } void CertificateToPIVCardCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } CertificateToPIVCardCommand::CertificateToPIVCardCommand(const std::string& cardSlot, const std::string &serialno) : CardCommand(new Private(this, cardSlot, serialno)) { } CertificateToPIVCardCommand::~CertificateToPIVCardCommand() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::~CertificateToPIVCardCommand()"; } void CertificateToPIVCardCommand::certificateToPIVCardDone(const Error &err) { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::certificateToPIVCardDone():" << err.asString() << "(" << err.code() << ")"; if (err) { #ifdef GPG_ERROR_HAS_NO_AUTH // gpgme 1.13 reports "BAD PIN" instead of "NO AUTH" if (err.code() == GPG_ERR_NO_AUTH || err.code() == GPG_ERR_BAD_PIN) { d->authenticate(); return; } #endif d->error(i18nc("@info", "Writing the certificate to the card failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { KMessageBox::information(d->parentWidgetOrView(), i18nc("@info", "Writing the certificate to the card succeeded."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } d->finished(); } void CertificateToPIVCardCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "CertificateToPIVCardCommand::doStart()"; d->start(); } void CertificateToPIVCardCommand::doCancel() { } #undef q_func #undef d_func diff --git a/src/commands/certifycertificatecommand.cpp b/src/commands/certifycertificatecommand.cpp index 829035a4f..fdd934a60 100644 --- a/src/commands/certifycertificatecommand.cpp +++ b/src/commands/certifycertificatecommand.cpp @@ -1,332 +1,332 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/signcertificatecommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2019 g10code GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "certifycertificatecommand.h" #include "newcertificatecommand.h" #include "command_p.h" #include "exportopenpgpcertstoservercommand.h" #include "dialogs/certifycertificatedialog.h" #include "utils/tags.h" #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #if GPGMEPP_VERSION >= 0x10E00 // 1.14.0 # define GPGME_HAS_REMARKS #endif using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; using namespace QGpgME; class CertifyCertificateCommand::Private : public Command::Private { friend class ::Kleo::Commands::CertifyCertificateCommand; CertifyCertificateCommand *q_func() const { return static_cast(q); } public: explicit Private(CertifyCertificateCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotDialogRejected(); void slotResult(const Error &err); void slotCertificationPrepared(); private: void ensureDialogCreated(); void createJob(); private: std::vector uids; QPointer dialog; QPointer job; }; CertifyCertificateCommand::Private *CertifyCertificateCommand::d_func() { return static_cast(d.get()); } const CertifyCertificateCommand::Private *CertifyCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() CertifyCertificateCommand::Private::Private(CertifyCertificateCommand *qq, KeyListController *c) : Command::Private(qq, c), uids(), dialog(), job() { } CertifyCertificateCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); if (dialog) { delete dialog; dialog = nullptr; } } CertifyCertificateCommand::CertifyCertificateCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const GpgME::Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const GpgME::UserID &uid) : Command(uid.parent(), new Private(this, nullptr)) { std::vector(1, uid).swap(d->uids); d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const std::vector &uids) : Command(uids.empty() ? Key() : uids.front().parent(), new Private(this, nullptr)) { d->uids = uids; d->init(); } void CertifyCertificateCommand::Private::init() { } CertifyCertificateCommand::~CertifyCertificateCommand() { qCDebug(KLEOPATRA_LOG); } void CertifyCertificateCommand::doStart() { const std::vector keys = d->keys(); if (keys.size() != 1 || keys.front().protocol() != GpgME::OpenPGP) { d->finished(); return; } std::vector secKeys; Q_FOREACH (const Key &secKey, KeyCache::instance()->secretKeys()) { // Only include usable keys. if (secKey.canCertify() && secKey.protocol() == OpenPGP && !secKey.isRevoked() && !secKey.isExpired() && !secKey.isInvalid()) { secKeys.push_back(secKey); } } if (secKeys.empty()) { auto sel = KMessageBox::questionYesNo(d->parentWidgetOrView(), xi18nc("@info", "To certify other certificates, you first need to create an OpenPGP certificate for yourself.") + QStringLiteral("

") + i18n("Do you wish to create one now?"), i18n("Certification Not Possible")); if (sel == KMessageBox::Yes) { QEventLoop loop; auto cmd = new Commands::NewCertificateCommand(); cmd->setParentWidget(d->parentWidgetOrView()); cmd->setProtocol(GpgME::OpenPGP); loop.connect(cmd, SIGNAL(finished()), SLOT(quit())); QMetaObject::invokeMethod(cmd, &Commands::NewCertificateCommand::start, Qt::QueuedConnection); loop.exec(); } else { Q_EMIT(canceled()); d->finished(); return; } Q_FOREACH (const Key &secKey, KeyCache::instance()->secretKeys()) { // Check again for secret keys if (secKey.canCertify() && secKey.protocol() == OpenPGP && !secKey.isRevoked() && !secKey.isExpired() && !secKey.isInvalid()) { secKeys.push_back(secKey); } } if (secKeys.empty()) { qCDebug(KLEOPATRA_LOG) << "Sec Keys still empty after keygen."; Q_EMIT(canceled()); d->finished(); return; } } const Key &key = keys.front(); for (const UserID &uid : std::as_const(d->uids)) if (qstricmp(uid.parent().primaryFingerprint(), key.primaryFingerprint()) != 0) { qCWarning(KLEOPATRA_LOG) << "User-ID <-> Key mismatch!"; d->finished(); return; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); Key target = d->key(); #ifdef GPGME_HAS_REMARKS if (!(target.keyListMode() & GpgME::SignatureNotations)) { target.update(); } #endif d->dialog->setCertificateToCertify(target); if (d->uids.size()) { d->dialog->setSelectedUserIDs(d->uids); } d->dialog->show(); } void CertifyCertificateCommand::Private::slotDialogRejected() { Q_EMIT q->canceled(); finished(); } void CertifyCertificateCommand::Private::slotResult(const Error &err) { if (!err && !err.isCanceled() && dialog && dialog->exportableCertificationSelected() && dialog->sendToServer()) { auto const cmd = new ExportOpenPGPCertsToServerCommand(key()); cmd->start(); } else if (!err) { information(i18n("Certification successful."), i18n("Certification Succeeded")); } else { error(i18n("

An error occurred while trying to certify

" "%1:

\t%2

", Formatting::formatForComboBox(key()), QString::fromUtf8(err.asString())), i18n("Certification Error")); } if (!dialog->tags().isEmpty()) { Tags::enableTags(); } finished(); } void CertifyCertificateCommand::Private::slotCertificationPrepared() { Q_ASSERT(dialog); createJob(); Q_ASSERT(job); job->setExportable(dialog->exportableCertificationSelected()); job->setNonRevocable(dialog->nonRevocableCertificationSelected()); job->setUserIDsToSign(dialog->selectedUserIDs()); job->setSigningKey(dialog->selectedSecretKey()); job->setCheckLevel(dialog->selectedCheckLevel()); #ifdef GPGME_HAS_REMARKS if (!dialog->tags().isEmpty()) { // do not set an empty remark to avoid an empty signature notation (GnuPG bug T5142) job->setRemark(dialog->tags()); } // This also came with 1.14.0 job->setDupeOk(true); #endif #ifdef QGPGME_SUPPORTS_TRUST_SIGNATURES if (dialog->trustSignatureSelected() && !dialog->trustSignatureDomain().isEmpty()) { // always create level 1 trust signatures with complete trust job->setTrustSignature(TrustSignatureTrust::Complete, 1, dialog->trustSignatureDomain()); } #endif #ifdef QGPGME_SUPPORTS_SIGNATURE_EXPIRATION if (!dialog->expirationDate().isNull()) { job->setExpirationDate(dialog->expirationDate()); } #endif if (const Error err = job->start(key())) { slotResult(err); } } void CertifyCertificateCommand::doCancel() { qCDebug(KLEOPATRA_LOG); if (d->job) { d->job->slotCancel(); } } void CertifyCertificateCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new CertifyCertificateDialog; applyWindowID(dialog); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); connect(dialog, SIGNAL(accepted()), q, SLOT(slotCertificationPrepared())); } void CertifyCertificateCommand::Private::createJob() { Q_ASSERT(!job); Q_ASSERT(key().protocol() == OpenPGP); const auto backend = QGpgME::openpgp(); if (!backend) { return; } SignKeyJob *const j = backend->signKeyJob(); if (!j) { return; } connect(j, &Job::progress, q, &Command::progress); connect(j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); job = j; } #undef d #undef q #include "moc_certifycertificatecommand.cpp" diff --git a/src/commands/changeownertrustcommand.cpp b/src/commands/changeownertrustcommand.cpp index eb7e586c2..2617ef415 100644 --- a/src/commands/changeownertrustcommand.cpp +++ b/src/commands/changeownertrustcommand.cpp @@ -1,239 +1,239 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/changeownertrustcommand.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 "changeownertrustcommand.h" #include "command_p.h" #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace GpgME; using namespace QGpgME; class ChangeOwnerTrustCommand::Private : public Command::Private { friend class ::Kleo::Commands::ChangeOwnerTrustCommand; ChangeOwnerTrustCommand *q_func() const { return static_cast(q); } public: explicit Private(ChangeOwnerTrustCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void ensureDialogCreated(); void createJob(); void showErrorDialog(const Error &error); void showSuccessDialog(); private: QPointer dialog; QPointer job; }; ChangeOwnerTrustCommand::Private *ChangeOwnerTrustCommand::d_func() { return static_cast(d.get()); } const ChangeOwnerTrustCommand::Private *ChangeOwnerTrustCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChangeOwnerTrustCommand::Private::Private(ChangeOwnerTrustCommand *qq, KeyListController *c) : Command::Private(qq, c), dialog(), job() { } ChangeOwnerTrustCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } ChangeOwnerTrustCommand::ChangeOwnerTrustCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } ChangeOwnerTrustCommand::ChangeOwnerTrustCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } ChangeOwnerTrustCommand::ChangeOwnerTrustCommand(const Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } void ChangeOwnerTrustCommand::Private::init() { } ChangeOwnerTrustCommand::~ChangeOwnerTrustCommand() { qCDebug(KLEOPATRA_LOG); } void ChangeOwnerTrustCommand::doStart() { if (d->keys().size() != 1) { d->finished(); return; } const Key key = d->key(); if (key.protocol() != GpgME::OpenPGP || (key.hasSecret() && key.ownerTrust() == Key::Ultimate)) { d->finished(); return; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); d->dialog->setHasSecretKey(key.hasSecret()); d->dialog->setFormattedCertificateName(Formatting::formatForComboBox(key)); d->dialog->setOwnerTrust(key.ownerTrust()); d->dialog->show(); } void ChangeOwnerTrustCommand::Private::slotDialogAccepted() { Q_ASSERT(dialog); const Key::OwnerTrust trust = dialog->ownerTrust(); qCDebug(KLEOPATRA_LOG) << "trust " << trust; createJob(); Q_ASSERT(job); if (const Error err = job->start(key(), trust)) { showErrorDialog(err); finished(); } } void ChangeOwnerTrustCommand::Private::slotDialogRejected() { Q_EMIT q->canceled(); finished(); } void ChangeOwnerTrustCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) ; else if (err) { showErrorDialog(err); } else { showSuccessDialog(); } finished(); } void ChangeOwnerTrustCommand::doCancel() { qCDebug(KLEOPATRA_LOG); if (d->job) { d->job->slotCancel(); } } void ChangeOwnerTrustCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new OwnerTrustDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void ChangeOwnerTrustCommand::Private::createJob() { Q_ASSERT(!job); const auto backend = (key().protocol() == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); if (!backend) { return; } ChangeOwnerTrustJob *const j = backend->changeOwnerTrustJob(); if (!j) { return; } connect(j, &Job::progress, q, &Command::progress); connect(j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); job = j; } void ChangeOwnerTrustCommand::Private::showErrorDialog(const Error &err) { error(i18n("

An error occurred while trying to change " "the certification trust for %1:

%2

", Formatting::formatForComboBox(key()), QString::fromLocal8Bit(err.asString())), i18n("Certification Trust Change Error")); } void ChangeOwnerTrustCommand::Private::showSuccessDialog() { information(i18n("Certification trust changed successfully."), i18n("Certification Trust Change Succeeded")); } #undef d #undef q #include "moc_changeownertrustcommand.cpp" diff --git a/src/commands/changepassphrasecommand.cpp b/src/commands/changepassphrasecommand.cpp index 2a86e134f..c5d0e01ae 100644 --- a/src/commands/changepassphrasecommand.cpp +++ b/src/commands/changepassphrasecommand.cpp @@ -1,202 +1,202 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/changepassphrasecommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "changepassphrasecommand.h" #include "command_p.h" #include #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; using namespace QGpgME; class ChangePassphraseCommand::Private : public Command::Private { friend class ::Kleo::Commands::ChangePassphraseCommand; ChangePassphraseCommand *q_func() const { return static_cast(q); } public: explicit Private(ChangePassphraseCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotResult(const Error &err); private: void createJob(); void startJob(); void showErrorDialog(const Error &error); void showSuccessDialog(); private: GpgME::Key key; QPointer job; }; ChangePassphraseCommand::Private *ChangePassphraseCommand::d_func() { return static_cast(d.get()); } const ChangePassphraseCommand::Private *ChangePassphraseCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChangePassphraseCommand::Private::Private(ChangePassphraseCommand *qq, KeyListController *c) : Command::Private(qq, c), key(), job() { } ChangePassphraseCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } ChangePassphraseCommand::ChangePassphraseCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } ChangePassphraseCommand::ChangePassphraseCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } ChangePassphraseCommand::ChangePassphraseCommand(const GpgME::Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } void ChangePassphraseCommand::Private::init() { } ChangePassphraseCommand::~ChangePassphraseCommand() { qCDebug(KLEOPATRA_LOG); } void ChangePassphraseCommand::doStart() { const std::vector keys = d->keys(); if (keys.size() != 1 || !keys.front().hasSecret()) { d->finished(); return; } d->key = keys.front(); d->createJob(); d->startJob(); } void ChangePassphraseCommand::Private::startJob() { const Error err = job ? job->start(key) : Error::fromCode(GPG_ERR_NOT_SUPPORTED) ; if (err) { showErrorDialog(err); finished(); } } void ChangePassphraseCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) ; else if (err) { showErrorDialog(err); } else { showSuccessDialog(); } finished(); } void ChangePassphraseCommand::doCancel() { qCDebug(KLEOPATRA_LOG); if (d->job) { d->job->slotCancel(); } } void ChangePassphraseCommand::Private::createJob() { Q_ASSERT(!job); const auto backend = (key.protocol() == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); if (!backend) { return; } ChangePasswdJob *const j = backend->changePasswdJob(); if (!j) { return; } connect(j, &Job::progress, q, &Command::progress); connect(j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); job = j; } void ChangePassphraseCommand::Private::showErrorDialog(const Error &err) { error(i18n("

An error occurred while trying to change " "the passphrase for %1:

%2

", Formatting::formatForComboBox(key), QString::fromLocal8Bit(err.asString())), i18n("Passphrase Change Error")); } void ChangePassphraseCommand::Private::showSuccessDialog() { information(i18n("Passphrase changed successfully."), i18n("Passphrase Change Succeeded")); } #undef d #undef q #include "moc_changepassphrasecommand.cpp" diff --git a/src/commands/changepincommand.cpp b/src/commands/changepincommand.cpp index 5a05156fb..9e22aa973 100644 --- a/src/commands/changepincommand.cpp +++ b/src/commands/changepincommand.cpp @@ -1,220 +1,220 @@ /* commands/changepincommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "changepincommand.h" #include "cardcommand_p.h" #include "smartcard/netkeycard.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; class ChangePinCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::ChangePinCommand; ChangePinCommand *q_func() const { return static_cast(q); } public: explicit Private(ChangePinCommand *qq, const std::string &serialNumber, const std::string &appName, QWidget *p); - ~Private(); + ~Private() override; void init(); private: void slotResult(const Error &err); private: void changePin(); private: std::string appName; std::string keyRef; ChangePinMode mode = NormalMode; }; ChangePinCommand::Private *ChangePinCommand::d_func() { return static_cast(d.get()); } const ChangePinCommand::Private *ChangePinCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChangePinCommand::Private::Private(ChangePinCommand *qq, const std::string &serialNumber, const std::string &appName_, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , appName(appName_) { } ChangePinCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::Private::~Private()"; } ChangePinCommand::ChangePinCommand(const std::string &serialNumber, const std::string &appName, QWidget *p) : CardCommand(new Private(this, serialNumber, appName, p)) { d->init(); } void ChangePinCommand::Private::init() { } ChangePinCommand::~ChangePinCommand() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::~ChangePinCommand()"; } void ChangePinCommand::setKeyRef(const std::string &keyRef) { d->keyRef = keyRef; } void ChangePinCommand::setMode(ChangePinMode mode) { d->mode = mode; } void ChangePinCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::doStart()"; d->changePin(); } void ChangePinCommand::doCancel() { } void ChangePinCommand::Private::changePin() { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::changePin()"; const auto card = SmartCard::ReaderStatus::instance()->getCard(serialNumber(), appName); if (!card) { error(i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } QByteArrayList command; command << "SCD PASSWD"; if (mode == ResetMode) { command << "--reset"; } else if (mode == NullPinMode) { command << "--nullpin"; } command << QByteArray::fromStdString(keyRef); ReaderStatus::mutableInstance()->startSimpleTransaction(card, command.join(' '), q, "slotResult"); } namespace { static QString errorMessage(const std::string &keyRef, ChangePinCommand::ChangePinMode mode, const QString &errorText) { // see cmd_passwd() in gpg-card.c if (keyRef == PIVCard::pukKeyRef()) { return i18nc("@info", "Changing the PUK failed: %1", errorText); } if (keyRef == OpenPGPCard::resetCodeKeyRef()) { return i18nc("@info", "Unblocking the PIN failed: %1", errorText); } if (keyRef == OpenPGPCard::adminPinKeyRef()) { return i18nc("@info", "Changing the Admin PIN failed: %1", errorText); } if (keyRef == OpenPGPCard::resetCodeKeyRef() && mode == ChangePinCommand::ResetMode) { return i18nc("@info", "Changing the Reset Code failed: %1", errorText); } if (keyRef == NetKeyCard::nksPinKeyRef()) { if (mode == ChangePinCommand::NullPinMode) { return i18nc("@info", "Setting the NKS PIN failed: %1", errorText); } else { return i18nc("@info", "Changing the NKS PIN failed: %1", errorText); } } if (keyRef == NetKeyCard::sigGPinKeyRef()) { if (mode == ChangePinCommand::NullPinMode) { return i18nc("@info", "Setting the SigG PIN failed: %1", errorText); } else { return i18nc("@info", "Changing the SigG PIN failed: %1", errorText); } } return i18nc("@info", "Changing the PIN failed: %1", errorText); } static QString successMessage(const std::string &keyRef, ChangePinCommand::ChangePinMode mode) { // see cmd_passwd() in gpg-card.c if (keyRef == PIVCard::pukKeyRef()) { return i18nc("@info", "PUK successfully changed."); } if (keyRef == OpenPGPCard::resetCodeKeyRef()) { return i18nc("@info", "Unblocked and set a new PIN successfully."); } if (keyRef == OpenPGPCard::adminPinKeyRef()) { return i18nc("@info", "Admin PIN changed successfully."); } if (keyRef == OpenPGPCard::resetCodeKeyRef() && mode == ChangePinCommand::ResetMode) { return i18nc("@info", "Reset Code changed successfully."); } if (keyRef == NetKeyCard::nksPinKeyRef()) { if (mode == ChangePinCommand::NullPinMode) { return i18nc("@info", "NKS PIN set successfully."); } else { return i18nc("@info", "NKS PIN changed successfully."); } } if (keyRef == NetKeyCard::sigGPinKeyRef()) { if (mode == ChangePinCommand::NullPinMode) { return i18nc("@info", "SigG PIN set successfully."); } else { return i18nc("@info", "SigG PIN changed successfully."); } } return i18nc("@info", "PIN changed successfully."); } } void ChangePinCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "ChangePinCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err) { error(errorMessage(keyRef, mode, QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { information(successMessage(keyRef, mode), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } finished(); } #undef d #undef q #include "moc_changepincommand.cpp" diff --git a/src/commands/changeroottrustcommand.cpp b/src/commands/changeroottrustcommand.cpp index 3371fd40d..fae96b2d3 100644 --- a/src/commands/changeroottrustcommand.cpp +++ b/src/commands/changeroottrustcommand.cpp @@ -1,360 +1,360 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/changeroottrustcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "changeroottrustcommand.h" #include "command_p.h" #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; class ChangeRootTrustCommand::Private : public QThread, public Command::Private { Q_OBJECT private: friend class ::Kleo::Commands::ChangeRootTrustCommand; ChangeRootTrustCommand *q_func() const { return static_cast(q); } public: explicit Private(ChangeRootTrustCommand *qq, KeyListController *c) : QThread(), Command::Private(qq, c), mutex(), trust(Key::Ultimate), trustListFile(QDir(gnupgHomeDirectory()).absoluteFilePath(QStringLiteral("trustlist.txt"))), canceled(false) { } private: void init() { q->setWarnWhenRunningAtShutdown(false); connect(this, SIGNAL(finished()), q_func(), SLOT(slotOperationFinished())); } void run() override; private: void slotOperationFinished() { KeyCache::mutableInstance()->enableFileSystemWatcher(true); if (error.isEmpty()) { KeyCache::mutableInstance()->reload(GpgME::CMS); } else Command::Private::error(i18n("Failed to update the trust database:\n" "%1", error), i18n("Root Trust Update Failed")); Command::Private::finished(); } private: mutable QMutex mutex; Key::OwnerTrust trust; QString trustListFile; QString gpgConfPath; QString error; volatile bool canceled; }; ChangeRootTrustCommand::Private *ChangeRootTrustCommand::d_func() { return static_cast(d.get()); } const ChangeRootTrustCommand::Private *ChangeRootTrustCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() ChangeRootTrustCommand::ChangeRootTrustCommand(KeyListController *p) : Command(new Private(this, p)) { d->init(); } ChangeRootTrustCommand::ChangeRootTrustCommand(QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { d->init(); } ChangeRootTrustCommand::ChangeRootTrustCommand(const GpgME::Key &key, KeyListController *p) : Command(new Private(this, p)) { Q_ASSERT(!key.isNull()); d->init(); setKey(key); } ChangeRootTrustCommand::ChangeRootTrustCommand(const GpgME::Key &key, QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { Q_ASSERT(!key.isNull()); d->init(); setKey(key); } ChangeRootTrustCommand::~ChangeRootTrustCommand() {} void ChangeRootTrustCommand::setTrust(Key::OwnerTrust trust) { Q_ASSERT(!d->isRunning()); const QMutexLocker locker(&d->mutex); d->trust = trust; } Key::OwnerTrust ChangeRootTrustCommand::trust() const { const QMutexLocker locker(&d->mutex); return d->trust; } void ChangeRootTrustCommand::setTrustListFile(const QString &trustListFile) { Q_ASSERT(!d->isRunning()); const QMutexLocker locker(&d->mutex); d->trustListFile = trustListFile; } QString ChangeRootTrustCommand::trustListFile() const { const QMutexLocker locker(&d->mutex); return d->trustListFile; } void ChangeRootTrustCommand::doStart() { const std::vector keys = d->keys(); Key key; if (keys.size() == 1) { key = keys.front(); } else { qCWarning(KLEOPATRA_LOG) << "can only work with one certificate at a time"; } if (key.isNull()) { d->Command::Private::finished(); return; } d->gpgConfPath = gpgConfPath(); KeyCache::mutableInstance()->enableFileSystemWatcher(false); d->start(); } void ChangeRootTrustCommand::doCancel() { const QMutexLocker locker(&d->mutex); d->canceled = true; } static QString change_trust_file(const QString &trustListFile, const QString &key, Key::OwnerTrust trust); static QString run_gpgconf_reload_gpg_agent(const QString &gpgConfPath); void ChangeRootTrustCommand::Private::run() { QMutexLocker locker(&mutex); const QString key = QString::fromLatin1(keys().front().primaryFingerprint()); const Key::OwnerTrust trust = this->trust; const QString trustListFile = this->trustListFile; const QString gpgConfPath = this->gpgConfPath; locker.unlock(); QString err = change_trust_file(trustListFile, key, trust); if (err.isEmpty()) { err = run_gpgconf_reload_gpg_agent(gpgConfPath); } locker.relock(); this->error = err; } static QString add_colons(const QString &fpr) { QString result; result.reserve(fpr.size() / 2 * 3 + 1); bool needColon = false; for (QChar ch : fpr) { result += ch; if (needColon) { result += QLatin1Char(':'); } needColon = !needColon; } if (result.endsWith(QLatin1Char(':'))) { result.chop(1); } return result; } namespace { // fix stupid default-finalize behaviour... class KFixedSaveFile : public QSaveFile { public: explicit KFixedSaveFile(const QString &fileName) : QSaveFile(fileName) {} - ~KFixedSaveFile() + ~KFixedSaveFile() override { cancelWriting(); } }; } // static QString change_trust_file(const QString &trustListFile, const QString &key, Key::OwnerTrust trust) { QList trustListFileContents; { QFile in(trustListFile); if (in.exists()) { // non-existence is not fatal... if (in.open(QIODevice::ReadOnly)) { trustListFileContents = in.readAll().split('\n'); } else { // ...but failure to open an existing file _is_ return i18n("Cannot open existing file \"%1\" for reading: %2", trustListFile, in.errorString()); } } // close, so KSaveFile doesn't clobber the original } KFixedSaveFile out(trustListFile); if (!out.open(QIODevice::WriteOnly)) return i18n("Cannot open file \"%1\" for reading and writing: %2", out.fileName() /*sic!*/, out.errorString()); if (!out.setPermissions(QFile::ReadOwner | QFile::WriteOwner)) return i18n("Cannot set restrictive permissions on file %1: %2", out.fileName() /*sic!*/, out.errorString()); const QString keyColon = add_colons(key); qCDebug(KLEOPATRA_LOG) << qPrintable(key) << " -> " << qPrintable(keyColon); // ( 1) ( 2 ) ( 3 )( 4) QRegExp rx(QLatin1String("\\s*(!?)\\s*([a-fA-F0-9]{40}|(?:[a-fA-F0-9]{2}:){19}[a-fA-F0-9]{2})\\s*([SsPp*])(.*)")); bool found = false; for (const QByteArray &rawLine : std::as_const(trustListFileContents)) { const QString line = QString::fromLatin1(rawLine.data(), rawLine.size()); if (!rx.exactMatch(line)) { qCDebug(KLEOPATRA_LOG) << "line \"" << rawLine.data() << "\" does not match"; out.write(rawLine + '\n'); continue; } const QString cap2 = rx.cap(2); if (cap2 != key && cap2 != keyColon) { qCDebug(KLEOPATRA_LOG) << qPrintable(key) << " != " << qPrintable(cap2) << " != " << qPrintable(keyColon); out.write(rawLine + '\n'); continue; } found = true; const bool disabled = rx.cap(1) == QLatin1Char('!'); const QByteArray flags = rx.cap(3).toLatin1(); const QByteArray rests = rx.cap(4).toLatin1(); if (trust == Key::Ultimate) if (!disabled) { // unchanged out.write(rawLine + '\n'); } else { out.write(keyColon.toLatin1() + ' ' + flags + rests + '\n'); } else if (trust == Key::Never) { if (disabled) { // unchanged out.write(rawLine + '\n'); } else { out.write('!' + keyColon.toLatin1() + ' ' + flags + rests + '\n'); } } // else: trust == Key::Unknown // -> don't write - ie.erase } if (!found) { // add if (trust == Key::Ultimate) { out.write(keyColon.toLatin1() + ' ' + 'S' + '\n'); } else if (trust == Key::Never) { out.write('!' + keyColon.toLatin1() + ' ' + 'S' + '\n'); } } if (!out.commit()) return i18n("Failed to move file %1 to its final destination, %2: %3", out.fileName(), trustListFile, out.errorString()); return QString(); } // static QString run_gpgconf_reload_gpg_agent(const QString &gpgConfPath) { if (gpgConfPath.isEmpty()) { return i18n("Could not find gpgconf executable"); } QProcess p; p.start(gpgConfPath, QStringList() << QStringLiteral("--reload") << QStringLiteral("gpg-agent")); qCDebug(KLEOPATRA_LOG) << "starting " << qPrintable(gpgConfPath) << " --reload gpg-agent"; p.waitForFinished(-1); qCDebug(KLEOPATRA_LOG) << "done"; if (p.error() == QProcess::UnknownError) { return QString(); } else { return i18n("\"gpgconf --reload gpg-agent\" failed: %1", p.errorString()); } } #undef q_func #undef d_func #include "moc_changeroottrustcommand.cpp" #include "changeroottrustcommand.moc" diff --git a/src/commands/checksumcreatefilescommand.cpp b/src/commands/checksumcreatefilescommand.cpp index b333b30cf..91122af70 100644 --- a/src/commands/checksumcreatefilescommand.cpp +++ b/src/commands/checksumcreatefilescommand.cpp @@ -1,170 +1,170 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/checksumcreatefilescommand.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 "checksumcreatefilescommand.h" #include "command_p.h" #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class ChecksumCreateFilesCommand::Private : public Command::Private { friend class ::Kleo::Commands::ChecksumCreateFilesCommand; ChecksumCreateFilesCommand *q_func() const { return static_cast(q); } public: explicit Private(ChecksumCreateFilesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QStringList selectFiles() const; void init(); private: void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: QStringList files; std::shared_ptr shared_qq; CreateChecksumsController controller; }; ChecksumCreateFilesCommand::Private *ChecksumCreateFilesCommand::d_func() { return static_cast(d.get()); } const ChecksumCreateFilesCommand::Private *ChecksumCreateFilesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChecksumCreateFilesCommand::Private::Private(ChecksumCreateFilesCommand *qq, KeyListController *c) : Command::Private(qq, c), files(), shared_qq(qq, [](ChecksumCreateFilesCommand*){}), controller() { controller.setAllowAddition(true); } ChecksumCreateFilesCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } ChecksumCreateFilesCommand::ChecksumCreateFilesCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } ChecksumCreateFilesCommand::ChecksumCreateFilesCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } ChecksumCreateFilesCommand::ChecksumCreateFilesCommand(const QStringList &files, KeyListController *c) : Command(new Private(this, c)) { d->init(); d->files = files; } ChecksumCreateFilesCommand::ChecksumCreateFilesCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->files = files; } void ChecksumCreateFilesCommand::Private::init() { controller.setExecutionContext(shared_qq); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } ChecksumCreateFilesCommand::~ChecksumCreateFilesCommand() { qCDebug(KLEOPATRA_LOG); } void ChecksumCreateFilesCommand::setFiles(const QStringList &files) { d->files = files; } void ChecksumCreateFilesCommand::doStart() { try { if (d->files.empty()) { d->files = d->selectFiles(); } if (d->files.empty()) { d->finished(); return; } d->controller.setFiles(d->files); d->controller.start(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Create Checksum Files Error")); d->finished(); } } void ChecksumCreateFilesCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } QStringList ChecksumCreateFilesCommand::Private::selectFiles() const { return FileDialog::getOpenFileNames(parentWidgetOrView(), i18n("Select One or More Files to Create Checksums For"), QStringLiteral("chk")); } #undef d #undef q #include "moc_checksumcreatefilescommand.cpp" diff --git a/src/commands/checksumverifyfilescommand.cpp b/src/commands/checksumverifyfilescommand.cpp index 4ce95f0cf..d367762b3 100644 --- a/src/commands/checksumverifyfilescommand.cpp +++ b/src/commands/checksumverifyfilescommand.cpp @@ -1,170 +1,170 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/checksumverifyfilescommand.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 "checksumverifyfilescommand.h" #include "command_p.h" #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class ChecksumVerifyFilesCommand::Private : public Command::Private { friend class ::Kleo::Commands::ChecksumVerifyFilesCommand; ChecksumVerifyFilesCommand *q_func() const { return static_cast(q); } public: explicit Private(ChecksumVerifyFilesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QStringList selectFiles() const; void init(); private: void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: QStringList files; std::shared_ptr shared_qq; VerifyChecksumsController controller; }; ChecksumVerifyFilesCommand::Private *ChecksumVerifyFilesCommand::d_func() { return static_cast(d.get()); } const ChecksumVerifyFilesCommand::Private *ChecksumVerifyFilesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ChecksumVerifyFilesCommand::Private::Private(ChecksumVerifyFilesCommand *qq, KeyListController *c) : Command::Private(qq, c), files(), shared_qq(qq, [](ChecksumVerifyFilesCommand *){}), controller() { } ChecksumVerifyFilesCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } ChecksumVerifyFilesCommand::ChecksumVerifyFilesCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } ChecksumVerifyFilesCommand::ChecksumVerifyFilesCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } ChecksumVerifyFilesCommand::ChecksumVerifyFilesCommand(const QStringList &files, KeyListController *c) : Command(new Private(this, c)) { d->init(); d->files = files; } ChecksumVerifyFilesCommand::ChecksumVerifyFilesCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->files = files; } void ChecksumVerifyFilesCommand::Private::init() { controller.setExecutionContext(shared_qq); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } ChecksumVerifyFilesCommand::~ChecksumVerifyFilesCommand() { qCDebug(KLEOPATRA_LOG); } void ChecksumVerifyFilesCommand::setFiles(const QStringList &files) { d->files = files; } void ChecksumVerifyFilesCommand::doStart() { try { if (d->files.empty()) { d->files = d->selectFiles(); } if (d->files.empty()) { d->finished(); return; } d->controller.setFiles(d->files); d->controller.start(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Verify Checksum Files Error")); d->finished(); } } void ChecksumVerifyFilesCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } QStringList ChecksumVerifyFilesCommand::Private::selectFiles() const { return FileDialog::getOpenFileNames(parentWidgetOrView(), i18n("Select One or More Checksum Files"), QStringLiteral("chk")); } #undef d #undef q #include "moc_checksumverifyfilescommand.cpp" diff --git a/src/commands/createcsrforcardkeycommand.cpp b/src/commands/createcsrforcardkeycommand.cpp index 6e4cea2e6..2612eb6bb 100644 --- a/src/commands/createcsrforcardkeycommand.cpp +++ b/src/commands/createcsrforcardkeycommand.cpp @@ -1,296 +1,296 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/createcsrforcardkeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "createcsrforcardkeycommand.h" #include "cardcommand_p.h" #include "dialogs/createcsrforcardkeydialog.h" #include "smartcard/netkeycard.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "utils/filedialog.h" #include "utils/keyparameters.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; using namespace QGpgME; class CreateCSRForCardKeyCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::CreateCSRForCardKeyCommand; CreateCSRForCardKeyCommand *q_func() const { return static_cast(q); } public: explicit Private(CreateCSRForCardKeyCommand *qq, const std::string &keyRef, const std::string &serialNumber, const std::string &appName, QWidget *parent); - ~Private(); + ~Private() override; private: void start(); void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const KeyGenerationResult &result, const QByteArray &request); QUrl saveRequest(const QByteArray &request); void ensureDialogCreated(); private: std::string appName; std::string keyRef; QStringList keyUsages; QPointer dialog; }; CreateCSRForCardKeyCommand::Private *CreateCSRForCardKeyCommand::d_func() { return static_cast(d.get()); } const CreateCSRForCardKeyCommand::Private *CreateCSRForCardKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() CreateCSRForCardKeyCommand::Private::Private(CreateCSRForCardKeyCommand *qq, const std::string &keyRef_, const std::string &serialNumber, const std::string &appName_, QWidget *parent) : CardCommand::Private(qq, serialNumber, parent) , appName(appName_) , keyRef(keyRef_) { } CreateCSRForCardKeyCommand::Private::~Private() { } namespace { QStringList getKeyUsages(const KeyPairInfo &keyInfo) { // note: gpgsm does not support creating CSRs for authentication certificates QStringList usages; if (keyInfo.canCertify()) { usages.push_back(QStringLiteral("cert")); } if (keyInfo.canSign()) { usages.push_back(QStringLiteral("sign")); } if (keyInfo.canEncrypt()) { usages.push_back(QStringLiteral("encrypt")); } return usages; } } void CreateCSRForCardKeyCommand::Private::start() { if (appName != NetKeyCard::AppName && appName != OpenPGPCard::AppName && appName != PIVCard::AppName) { qCWarning(KLEOPATRA_LOG) << "CreateCSRForCardKeyCommand does not support card application" << QString::fromStdString(appName); finished(); return; } const auto card = ReaderStatus::instance()->getCard(serialNumber(), appName); if (!card) { error(i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const KeyPairInfo &keyInfo = card->keyInfo(keyRef); keyUsages = getKeyUsages(keyInfo); ensureDialogCreated(); dialog->setWindowTitle(i18n("Certificate Details")); if (!card->cardHolder().isEmpty()) { dialog->setName(card->cardHolder()); } dialog->show(); } void CreateCSRForCardKeyCommand::Private::slotDialogAccepted() { const Error err = ReaderStatus::switchCardAndApp(serialNumber(), appName); if (err) { finished(); return; } const auto backend = smime(); if (!backend) { finished(); return; } KeyGenerationJob *const job = backend->keyGenerationJob(); if (!job) { finished(); return; } Job::context(job)->setArmor(true); connect(job, SIGNAL(result(const GpgME::KeyGenerationResult &, const QByteArray &)), q, SLOT(slotResult(const GpgME::KeyGenerationResult &, const QByteArray &))); KeyParameters keyParameters(KeyParameters::CMS); keyParameters.setKeyType(QString::fromStdString(keyRef)); keyParameters.setKeyUsages(keyUsages); keyParameters.setDN(dialog->dn()); keyParameters.setEmail(dialog->email()); if (const Error err = job->start(keyParameters.toString())) { error(i18nc("@info", "Creating a CSR for the card key failed:\n%1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); finished(); } } void CreateCSRForCardKeyCommand::Private::slotDialogRejected() { canceled(); } void CreateCSRForCardKeyCommand::Private::slotResult(const KeyGenerationResult &result, const QByteArray &request) { if (result.error().isCanceled()) { // do nothing } else if (result.error()) { error(i18nc("@info", "Creating a CSR for the card key failed:\n%1", QString::fromUtf8(result.error().asString())), i18nc("@title", "Error")); } else { const QUrl url = saveRequest(request); if (!url.isEmpty()) { information(xi18nc("@info", "Successfully wrote request to %1." "You should now send the request to the Certification Authority (CA).", url.toLocalFile()), i18nc("@title", "Request Saved")); } } finished(); } namespace { struct SaveToFileResult { QUrl url; QString errorMessage; }; SaveToFileResult saveRequestToFile(const QString &filename, const QByteArray &request, QIODevice::OpenMode mode) { QFile file(filename); if (file.open(mode)) { const auto bytesWritten = file.write(request); if (bytesWritten < request.size()) { return { QUrl(), file.errorString() }; } return { QUrl::fromLocalFile(file.fileName()), QString() }; } return { QUrl(), file.errorString() }; } } QUrl CreateCSRForCardKeyCommand::Private::saveRequest(const QByteArray &request) { const QString proposedFilename = QLatin1String("request_%1.p10").arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd_HHmmss"))); while (true) { const QString filePath = FileDialog::getSaveFileNameEx( parentWidgetOrView(), i18nc("@title", "Save Request"), QStringLiteral("save_csr"), proposedFilename, i18n("PKCS#10 Requests (*.p10)")); if (filePath.isEmpty()) { // user canceled the dialog return QUrl(); } const auto result = saveRequestToFile(filePath, request, QIODevice::NewOnly); if (result.url.isEmpty()) { qCDebug(KLEOPATRA_LOG) << "Writing request to file" << filePath << "failed:" << result.errorMessage; error(xi18nc("@info", "Saving the request failed.%1", result.errorMessage), i18nc("@title", "Error Saving Request")); } else { return result.url; } } } void CreateCSRForCardKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new CreateCSRForCardKeyDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } CreateCSRForCardKeyCommand::CreateCSRForCardKeyCommand(const std::string &keyRef, const std::string &serialNumber, const std::string &appName, QWidget *parent) : CardCommand(new Private(this, keyRef, serialNumber, appName, parent)) { } CreateCSRForCardKeyCommand::~CreateCSRForCardKeyCommand() { } void CreateCSRForCardKeyCommand::doStart() { d->start(); } void CreateCSRForCardKeyCommand::doCancel() { } #undef d #undef q #include "moc_createcsrforcardkeycommand.cpp" diff --git a/src/commands/createopenpgpkeyfromcardkeyscommand.cpp b/src/commands/createopenpgpkeyfromcardkeyscommand.cpp index 72d76c73c..87bef07a9 100644 --- a/src/commands/createopenpgpkeyfromcardkeyscommand.cpp +++ b/src/commands/createopenpgpkeyfromcardkeyscommand.cpp @@ -1,222 +1,222 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/createopenpgpkeyfromcardkeyscommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "createopenpgpkeyfromcardkeyscommand.h" #include "cardcommand_p.h" #include "dialogs/adduseriddialog.h" #include "smartcard/netkeycard.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; using namespace QGpgME; class CreateOpenPGPKeyFromCardKeysCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::CreateOpenPGPKeyFromCardKeysCommand; CreateOpenPGPKeyFromCardKeysCommand *q_func() const { return static_cast(q); } public: explicit Private(CreateOpenPGPKeyFromCardKeysCommand *qq, const std::string &serialNumber, const std::string &appName, QWidget *parent); - ~Private(); + ~Private() override; private: void start(); void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); void ensureDialogCreated(); private: std::string appName; QPointer dialog; }; CreateOpenPGPKeyFromCardKeysCommand::Private *CreateOpenPGPKeyFromCardKeysCommand::d_func() { return static_cast(d.get()); } const CreateOpenPGPKeyFromCardKeysCommand::Private *CreateOpenPGPKeyFromCardKeysCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() CreateOpenPGPKeyFromCardKeysCommand::Private::Private(CreateOpenPGPKeyFromCardKeysCommand *qq, const std::string &serialNumber, const std::string &appName_, QWidget *parent) : CardCommand::Private(qq, serialNumber, parent) , appName(appName_) { } CreateOpenPGPKeyFromCardKeysCommand::Private::~Private() { } void CreateOpenPGPKeyFromCardKeysCommand::Private::start() { if (appName != NetKeyCard::AppName && appName != OpenPGPCard::AppName && appName != PIVCard::AppName) { qCWarning(KLEOPATRA_LOG) << "CreateOpenPGPKeyFromCardKeysCommand does not support card application" << QString::fromStdString(appName); finished(); return; } const auto card = ReaderStatus::instance()->getCard(serialNumber(), appName); if (!card) { error(i18n("Failed to find the smartcard with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const auto signingKeyGrip = card->keyInfo(card->signingKeyRef()).grip; const Key signingKey = KeyCache::instance()->findSubkeyByKeyGrip(signingKeyGrip, OpenPGP).parent(); if (!signingKey.isNull()) { const QString message = i18nc("@info", "

There is already an OpenPGP key corresponding to the signing key on this card:

%1

" "

Do you still want to create an OpenPGP key for the card keys?

", Formatting::summaryLine(signingKey)); const auto choice = KMessageBox::warningContinueCancel(parentWidgetOrView(), message, i18nc("@title:window", "Create OpenPGP Key"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify); if (choice != KMessageBox::Continue) { finished(); return; } } ensureDialogCreated(); dialog->setWindowTitle(i18n("Enter User ID")); dialog->setName(card->cardHolder()); dialog->show(); } void CreateOpenPGPKeyFromCardKeysCommand::Private::slotDialogAccepted() { const Error err = ReaderStatus::switchCardAndApp(serialNumber(), appName); if (err) { finished(); return; } const auto backend = openpgp(); if (!backend) { finished(); return; } QuickJob *const job = backend->quickJob(); if (!job) { finished(); return; } connect(job, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); const QString userID = Formatting::prettyNameAndEMail(OpenPGP, QString(), dialog->name(), dialog->email(), dialog->comment()); const QDateTime expires = QDateTime(); const unsigned int flags = GPGME_CREATE_FORCE; job->startCreate(userID, "card", expires, Key(), flags); } void CreateOpenPGPKeyFromCardKeysCommand::Private::slotDialogRejected() { canceled(); } void CreateOpenPGPKeyFromCardKeysCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) { // do nothing } else if (err) { error(i18nc("@info", "Creating an OpenPGP key from the card keys failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } else { information(i18nc("@info", "Successfully generated an OpenPGP key from the card keys."), i18nc("@title", "Success")); } finished(); } void CreateOpenPGPKeyFromCardKeysCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new AddUserIDDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } CreateOpenPGPKeyFromCardKeysCommand::CreateOpenPGPKeyFromCardKeysCommand(const std::string &serialNumber, const std::string &appName, QWidget *parent) : CardCommand(new Private(this, serialNumber, appName, parent)) { } CreateOpenPGPKeyFromCardKeysCommand::~CreateOpenPGPKeyFromCardKeysCommand() { } // static bool CreateOpenPGPKeyFromCardKeysCommand::isSupported() { return !(engineInfo(GpgEngine).engineVersion() < "2.3.0"); } void CreateOpenPGPKeyFromCardKeysCommand::doStart() { d->start(); } void CreateOpenPGPKeyFromCardKeysCommand::doCancel() { } #undef d #undef q #include "moc_createopenpgpkeyfromcardkeyscommand.cpp" diff --git a/src/commands/decryptverifyclipboardcommand.cpp b/src/commands/decryptverifyclipboardcommand.cpp index 4d56f4396..57160fa63 100644 --- a/src/commands/decryptverifyclipboardcommand.cpp +++ b/src/commands/decryptverifyclipboardcommand.cpp @@ -1,173 +1,173 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/decryptverifyclipboardcommand.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 "decryptverifyclipboardcommand.h" #ifndef QT_NO_CLIPBOARD #include "command_p.h" #include #include #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class DecryptVerifyClipboardCommand::Private : public Command::Private { friend class ::Kleo::Commands::DecryptVerifyClipboardCommand; DecryptVerifyClipboardCommand *q_func() const { return static_cast(q); } public: explicit Private(DecryptVerifyClipboardCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: std::shared_ptr shared_qq; std::shared_ptr input; DecryptVerifyEMailController controller; }; DecryptVerifyClipboardCommand::Private *DecryptVerifyClipboardCommand::d_func() { return static_cast(d.get()); } const DecryptVerifyClipboardCommand::Private *DecryptVerifyClipboardCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DecryptVerifyClipboardCommand::Private::Private(DecryptVerifyClipboardCommand *qq, KeyListController *c) : Command::Private(qq, c), shared_qq(qq, [](DecryptVerifyClipboardCommand*){}), input(), controller() { } DecryptVerifyClipboardCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } DecryptVerifyClipboardCommand::DecryptVerifyClipboardCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } DecryptVerifyClipboardCommand::DecryptVerifyClipboardCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void DecryptVerifyClipboardCommand::Private::init() { controller.setExecutionContext(shared_qq); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } DecryptVerifyClipboardCommand::~DecryptVerifyClipboardCommand() { qCDebug(KLEOPATRA_LOG); } // static bool DecryptVerifyClipboardCommand::canDecryptVerifyCurrentClipboard() { try { return Input::createFromClipboard()->classification() & (Class::CipherText | Class::ClearsignedMessage | Class::OpaqueSignature); } catch (...) {} return false; } void DecryptVerifyClipboardCommand::doStart() { try { const std::shared_ptr input = Input::createFromClipboard(); const unsigned int classification = input->classification(); if (classification & (Class::ClearsignedMessage | Class::OpaqueSignature)) { d->controller.setOperation(Verify); d->controller.setVerificationMode(Opaque); } else if (classification & Class::CipherText) { d->controller.setOperation(DecryptVerify); } else { d->information(i18n("The clipboard does not appear to " "contain a signature or encrypted text."), i18n("Decrypt/Verify Clipboard Error")); d->finished(); return; } d->controller.setProtocol(findProtocol(classification)); d->controller.setInput(input); d->controller.setOutput(Output::createFromClipboard()); d->controller.start(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Decrypt/Verify Clipboard Error")); d->finished(); } } void DecryptVerifyClipboardCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } #undef d #undef q #include "moc_decryptverifyclipboardcommand.cpp" #endif // QT_NO_CLIPBOARD diff --git a/src/commands/decryptverifyfilescommand.cpp b/src/commands/decryptverifyfilescommand.cpp index c90479bb7..7411b5b4c 100644 --- a/src/commands/decryptverifyfilescommand.cpp +++ b/src/commands/decryptverifyfilescommand.cpp @@ -1,193 +1,193 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/decryptverifyfilescommand.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 "decryptverifyfilescommand.h" #include "fileoperationspreferences.h" #include "command_p.h" #include "crypto/decryptverifyfilescontroller.h" #include "crypto/autodecryptverifyfilescontroller.h" #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class DecryptVerifyFilesCommand::Private : public Command::Private { friend class ::Kleo::Commands::DecryptVerifyFilesCommand; DecryptVerifyFilesCommand *q_func() const { return static_cast(q); } public: explicit Private(DecryptVerifyFilesCommand *qq, KeyListController *c, bool forceManualMode=false); - ~Private(); + ~Private() override; QStringList selectFiles() const; void init(); private: void slotControllerDone() { finished(); } void slotControllerError(int, const QString &msg) { KMessageBox::error(parentWidgetOrView(), msg, i18n("Decrypt/Verify Failed")); finished(); } private: QStringList files; std::shared_ptr shared_qq; DecryptVerifyFilesController *mController; }; DecryptVerifyFilesCommand::Private *DecryptVerifyFilesCommand::d_func() { return static_cast(d.get()); } const DecryptVerifyFilesCommand::Private *DecryptVerifyFilesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DecryptVerifyFilesCommand::Private::Private(DecryptVerifyFilesCommand *qq, KeyListController *c, bool forceManualMode) : Command::Private(qq, c), files(), shared_qq(qq, [](DecryptVerifyFilesCommand*){}) { FileOperationsPreferences prefs; if (!forceManualMode && GpgME::hasFeature(0, GpgME::BinaryAndFineGrainedIdentify) && prefs.autoDecryptVerify()) { mController = new AutoDecryptVerifyFilesController(); } else { mController = new DecryptVerifyFilesController(); } } DecryptVerifyFilesCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); delete mController; } DecryptVerifyFilesCommand::DecryptVerifyFilesCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } DecryptVerifyFilesCommand::DecryptVerifyFilesCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } DecryptVerifyFilesCommand::DecryptVerifyFilesCommand(const QStringList &files, KeyListController *c, bool forceManualMode) : Command(new Private(this, c, forceManualMode)) { d->init(); d->files = files; } DecryptVerifyFilesCommand::DecryptVerifyFilesCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->files = files; } void DecryptVerifyFilesCommand::Private::init() { mController->setExecutionContext(shared_qq); connect(mController, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(mController, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } DecryptVerifyFilesCommand::~DecryptVerifyFilesCommand() { qCDebug(KLEOPATRA_LOG); } void DecryptVerifyFilesCommand::setFiles(const QStringList &files) { d->files = files; } void DecryptVerifyFilesCommand::setOperation(DecryptVerifyOperation op) { try { d->mController->setOperation(op); } catch (...) {} } DecryptVerifyOperation DecryptVerifyFilesCommand::operation() const { return d->mController->operation(); } void DecryptVerifyFilesCommand::doStart() { try { if (d->files.empty()) { d->files = d->selectFiles(); } if (d->files.empty()) { d->finished(); return; } d->mController->setFiles(d->files); d->mController->start(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Decrypt/Verify Files Error")); d->finished(); } } void DecryptVerifyFilesCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->mController->cancel(); } QStringList DecryptVerifyFilesCommand::Private::selectFiles() const { return FileDialog::getOpenFileNames(parentWidgetOrView(), i18n("Select One or More Files to Decrypt and/or Verify"), QStringLiteral("enc")); } #undef d #undef q #include "moc_decryptverifyfilescommand.cpp" diff --git a/src/commands/deletecertificatescommand.cpp b/src/commands/deletecertificatescommand.cpp index 6d54ce8ae..3e8763206 100644 --- a/src/commands/deletecertificatescommand.cpp +++ b/src/commands/deletecertificatescommand.cpp @@ -1,429 +1,429 @@ /* -*- mode: c++; c-basic-offset:4 -*- deleteCertificatescommand.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 "deletecertificatescommand.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GpgME; using namespace Kleo; using namespace Kleo::Dialogs; using namespace QGpgME; class DeleteCertificatesCommand::Private : public Command::Private { friend class ::Kleo::DeleteCertificatesCommand; DeleteCertificatesCommand *q_func() const { return static_cast(q); } public: explicit Private(DeleteCertificatesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void startDeleteJob(GpgME::Protocol protocol); void cancelJobs(); void pgpDeleteResult(const GpgME::Error &); void cmsDeleteResult(const GpgME::Error &); void showErrorsAndFinish(); bool canDelete(GpgME::Protocol proto) const { if (const auto cbp = (proto == GpgME::OpenPGP ? QGpgME::openpgp() : QGpgME::smime())) if (DeleteJob *const job = cbp->deleteJob()) { job->slotCancel(); return true; } return false; } void ensureDialogCreated() { if (dialog) { return; } dialog = new DeleteCertificatesDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setWindowTitle(i18nc("@title:window", "Delete Certificates")); connect(dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected())); } void ensureDialogShown() { if (dialog) { dialog->show(); } } void slotDialogAccepted(); void slotDialogRejected() { canceled(); } private: QPointer dialog; QPointer cmsJob, pgpJob; GpgME::Error cmsError, pgpError; std::vector cmsKeys, pgpKeys; }; DeleteCertificatesCommand::Private *DeleteCertificatesCommand::d_func() { return static_cast(d.get()); } const DeleteCertificatesCommand::Private *DeleteCertificatesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DeleteCertificatesCommand::Private::Private(DeleteCertificatesCommand *qq, KeyListController *c) : Command::Private(qq, c) { } DeleteCertificatesCommand::Private::~Private() {} DeleteCertificatesCommand::DeleteCertificatesCommand(KeyListController *p) : Command(new Private(this, p)) { } DeleteCertificatesCommand::DeleteCertificatesCommand(QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { } DeleteCertificatesCommand::~DeleteCertificatesCommand() {} namespace { enum Action { Nothing = 0, Failure = 1, ClearCMS = 2, ClearPGP = 4 }; // const unsigned int errorCase = // openpgp.empty() << 3U | d->canDelete( OpenPGP ) << 2U | // cms.empty() << 1U | d->canDelete( CMS ) << 0U ; static const struct { const char *text; Action actions; } deletionErrorCases[16] = { // if havePGP // if cantPGP // if haveCMS { I18N_NOOP("Neither the OpenPGP nor the CMS " "backends support certificate deletion.\n" "Check your installation."), Failure }, // cantCMS { I18N_NOOP("The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation.\n" "Only the selected CMS certificates " "will be deleted."), ClearPGP }, // canCMS // if !haveCMS { I18N_NOOP("The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation."), Failure }, { I18N_NOOP("The OpenPGP backend does not support " "certificate deletion.\n" "Check your installation."), Failure }, // if canPGP // if haveCMS { I18N_NOOP("The CMS backend does not support " "certificate deletion.\n" "Check your installation.\n" "Only the selected OpenPGP certificates " "will be deleted."), ClearCMS }, // cantCMS { nullptr, Nothing }, // canCMS // if !haveCMS { nullptr, Nothing }, // cantCMS { nullptr, Nothing }, // canCMS // if !havePGP // if cantPGP // if haveCMS { I18N_NOOP("The CMS backend does not support " "certificate deletion.\n" "Check your installation."), Failure }, // cantCMS { nullptr, Nothing }, // canCMS // if !haveCMS { nullptr, Nothing }, // cantCMS { nullptr, Nothing }, // canCMS // if canPGP // if haveCMS { I18N_NOOP("The CMS backend does not support " "certificate deletion.\n" "Check your installation."), Failure }, // cantCMS { nullptr, Nothing }, // canCMS // if !haveCMS { nullptr, Nothing }, // cantCMS { nullptr, Nothing }, // canCMS }; } // anon namespace void DeleteCertificatesCommand::doStart() { std::vector selected = d->keys(); if (selected.empty()) { d->finished(); return; } std::sort(selected.begin(), selected.end(), _detail::ByFingerprint()); // Calculate the closure of the selected keys (those that need to // be deleted with them, though not selected themselves): std::vector toBeDeleted = KeyCache::instance()->findSubjects(selected); std::sort(toBeDeleted.begin(), toBeDeleted.end(), _detail::ByFingerprint()); std::vector unselected; unselected.reserve(toBeDeleted.size()); std::set_difference(toBeDeleted.begin(), toBeDeleted.end(), selected.begin(), selected.end(), std::back_inserter(unselected), _detail::ByFingerprint()); d->ensureDialogCreated(); d->dialog->setSelectedKeys(selected); d->dialog->setUnselectedKeys(unselected); d->ensureDialogShown(); } void DeleteCertificatesCommand::Private::slotDialogAccepted() { std::vector keys = dialog->keys(); Q_ASSERT(!keys.empty()); auto pgpBegin = keys.begin(); auto pgpEnd = std::stable_partition(pgpBegin, keys.end(), [](const GpgME::Key &key) { return key.protocol() != GpgME::CMS; }); auto cmsBegin = pgpEnd; auto cmsEnd = keys.end(); std::vector openpgp(pgpBegin, pgpEnd); std::vector cms(cmsBegin, cmsEnd); const unsigned int errorCase = openpgp.empty() << 3U | canDelete(OpenPGP) << 2U | cms.empty() << 1U | canDelete(CMS) << 0U; if (const unsigned int actions = deletionErrorCases[errorCase].actions) { information(i18n(deletionErrorCases[errorCase].text), (actions & Failure) ? i18n("Certificate Deletion Failed") : i18n("Certificate Deletion Problem")); if (actions & ClearCMS) { cms.clear(); } if (actions & ClearPGP) { openpgp.clear(); } if (actions & Failure) { canceled(); return; } } Q_ASSERT(!openpgp.empty() || !cms.empty()); pgpKeys.swap(openpgp); cmsKeys.swap(cms); if (!pgpKeys.empty()) { startDeleteJob(GpgME::OpenPGP); } if (!cmsKeys.empty()) { startDeleteJob(GpgME::CMS); } if ((pgpKeys.empty() || pgpError.code()) && (cmsKeys.empty() || cmsError.code())) { showErrorsAndFinish(); } } void DeleteCertificatesCommand::Private::startDeleteJob(GpgME::Protocol protocol) { Q_ASSERT(protocol != GpgME::UnknownProtocol); const std::vector &keys = protocol == CMS ? cmsKeys : pgpKeys; const auto backend = (protocol == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); Q_ASSERT(backend); std::unique_ptr job(new MultiDeleteJob(backend)); if (protocol == CMS) connect(job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)), q_func(), SLOT(cmsDeleteResult(GpgME::Error))); else connect(job.get(), SIGNAL(result(GpgME::Error,GpgME::Key)), q_func(), SLOT(pgpDeleteResult(GpgME::Error))); connect(job.get(), &Job::progress, q, &Command::progress); if (const Error err = job->start(keys, true /*allowSecretKeyDeletion*/)) { (protocol == CMS ? cmsError : pgpError) = err; } else { (protocol == CMS ? cmsJob : pgpJob) = job.release(); } } void DeleteCertificatesCommand::Private::showErrorsAndFinish() { Q_ASSERT(!pgpJob); Q_ASSERT(!cmsJob); if (pgpError || cmsError) { QString pgpErrorString; if (pgpError) { pgpErrorString = i18n("OpenPGP backend: %1", QString::fromLocal8Bit(pgpError.asString())); } QString cmsErrorString; if (cmsError) { cmsErrorString = i18n("CMS backend: %1", QString::fromLocal8Bit(cmsError.asString())); } const QString msg = i18n("

An error occurred while trying to delete " "the certificate:

" "

%1

", pgpError ? cmsError ? pgpErrorString + QLatin1String("
") + cmsErrorString : pgpErrorString : cmsErrorString); error(msg, i18n("Certificate Deletion Failed")); } else if (!pgpError.isCanceled() && !cmsError.isCanceled()) { std::vector keys = pgpKeys; keys.insert(keys.end(), cmsKeys.begin(), cmsKeys.end()); KeyCache::mutableInstance()->remove(keys); } finished(); } void DeleteCertificatesCommand::doCancel() { d->cancelJobs(); } void DeleteCertificatesCommand::Private::pgpDeleteResult(const Error &err) { pgpError = err; pgpJob = nullptr; if (!cmsJob) { showErrorsAndFinish(); } } void DeleteCertificatesCommand::Private::cmsDeleteResult(const Error &err) { cmsError = err; cmsJob = nullptr; if (!pgpJob) { showErrorsAndFinish(); } } void DeleteCertificatesCommand::Private::cancelJobs() { if (cmsJob) { cmsJob->slotCancel(); } if (pgpJob) { pgpJob->slotCancel(); } } #undef d #undef q #include "moc_deletecertificatescommand.cpp" diff --git a/src/commands/detailscommand.cpp b/src/commands/detailscommand.cpp index fcb2de32c..2eecf2fd5 100644 --- a/src/commands/detailscommand.cpp +++ b/src/commands/detailscommand.cpp @@ -1,162 +1,162 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/detailscommand.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 "detailscommand.h" #include "command_p.h" #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; class DetailsCommand::Private : public Command::Private { friend class ::Kleo::Commands::DetailsCommand; DetailsCommand *q_func() const { return static_cast(q); } public: explicit Private(DetailsCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; private: void ensureDialogCreated() { if (dialog) { return; } auto dlg = new CertificateDetailsDialog; applyWindowID(dlg); dlg->setAttribute(Qt::WA_DeleteOnClose); connect(dlg, &QDialog::finished, q_func(), [this] (int) { slotDialogClosed(); }); dialog = dlg; } void ensureDialogVisible() { ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } } void init() { q->setWarnWhenRunningAtShutdown(false); } private: void slotDialogClosed(); private: QPointer dialog; }; DetailsCommand::Private *DetailsCommand::d_func() { return static_cast(d.get()); } const DetailsCommand::Private *DetailsCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() DetailsCommand::Private::Private(DetailsCommand *qq, KeyListController *c) : Command::Private(qq, c), dialog() { } DetailsCommand::Private::~Private() {} DetailsCommand::DetailsCommand(KeyListController *p) : Command(new Private(this, p)) { d->init(); } DetailsCommand::DetailsCommand(QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { d->init(); } DetailsCommand::DetailsCommand(const Key &key, KeyListController *p) : Command(new Private(this, p)) { Q_ASSERT(!key.isNull()); d->init(); setKey(key); } DetailsCommand::DetailsCommand(const Key &key, QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { Q_ASSERT(!key.isNull()); d->init(); setKey(key); } DetailsCommand::~DetailsCommand() {} void DetailsCommand::doStart() { const std::vector keys = d->keys(); Key key; if (keys.size() == 1) { key = keys.front(); } else { qCWarning(KLEOPATRA_LOG) << "can only work with one certificate at a time"; } if (key.isNull()) { d->finished(); return; } d->ensureDialogCreated(); d->dialog->setKey(key); d->ensureDialogVisible(); } void DetailsCommand::doCancel() { if (d->dialog) { d->dialog->close(); } } void DetailsCommand::Private::slotDialogClosed() { finished(); } #undef q_func #undef d_func #include "moc_detailscommand.cpp" diff --git a/src/commands/dumpcertificatecommand.cpp b/src/commands/dumpcertificatecommand.cpp index f6d723696..9b491ef0a 100644 --- a/src/commands/dumpcertificatecommand.cpp +++ b/src/commands/dumpcertificatecommand.cpp @@ -1,343 +1,343 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/dumpcertificatecommand.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 "dumpcertificatecommand.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds namespace { class DumpCertificateDialog : public QDialog { Q_OBJECT public: explicit DumpCertificateDialog(QWidget *parent = nullptr) : QDialog(parent), ui(this) { resize(600, 500); } Q_SIGNALS: void updateRequested(); public Q_SLOTS: void append(const QString &line) { ui.logTextWidget.append(line); ui.logTextWidget.ensureCursorVisible(); } void clear() { ui.logTextWidget.clear(); } private: struct Ui { QTextEdit logTextWidget; QPushButton updateButton, closeButton; QVBoxLayout vlay; QHBoxLayout hlay; explicit Ui(DumpCertificateDialog *q) : logTextWidget(q), updateButton(i18nc("@action:button Update the log text widget", "&Update"), q), closeButton(q), vlay(q), hlay() { KGuiItem::assign(&closeButton, KStandardGuiItem::close()); KDAB_SET_OBJECT_NAME(logTextWidget); KDAB_SET_OBJECT_NAME(updateButton); KDAB_SET_OBJECT_NAME(closeButton); KDAB_SET_OBJECT_NAME(vlay); KDAB_SET_OBJECT_NAME(hlay); logTextWidget.setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); logTextWidget.setReadOnly(true); vlay.addWidget(&logTextWidget, 1); vlay.addLayout(&hlay); hlay.addWidget(&updateButton); hlay.addStretch(1); hlay.addWidget(&closeButton); connect(&updateButton, &QAbstractButton::clicked, q, &DumpCertificateDialog::updateRequested); connect(&closeButton, &QAbstractButton::clicked, q, &QWidget::close); } } ui; }; } using namespace Kleo; using namespace Kleo::Commands; static QByteArray chomped(QByteArray ba) { while (ba.endsWith('\n') || ba.endsWith('\r')) { ba.chop(1); } return ba; } class DumpCertificateCommand::Private : Command::Private { friend class ::Kleo::Commands::DumpCertificateCommand; DumpCertificateCommand *q_func() const { return static_cast(q); } public: explicit Private(DumpCertificateCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QString errorString() const { return QString::fromLocal8Bit(errorBuffer); } private: void init(); void refreshView(); private: void slotProcessFinished(int, QProcess::ExitStatus); void slotProcessReadyReadStandardOutput() { while (process.canReadLine()) { const QString line = Kleo::stringFromGpgOutput(chomped(process.readLine())); if (dialog) { dialog->append(line); } outputBuffer.push_back(line); } } void slotProcessReadyReadStandardError() { errorBuffer += process.readAllStandardError(); } void slotUpdateRequested() { if (process.state() == QProcess::NotRunning) { refreshView(); } } void slotDialogDestroyed() { dialog = nullptr; if (process.state() != QProcess::NotRunning) { q->cancel(); } else { finished(); } } private: QPointer dialog; KProcess process; QByteArray errorBuffer; QStringList outputBuffer; bool useDialog; bool canceled; }; DumpCertificateCommand::Private *DumpCertificateCommand::d_func() { return static_cast(d.get()); } const DumpCertificateCommand::Private *DumpCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DumpCertificateCommand::Private::Private(DumpCertificateCommand *qq, KeyListController *c) : Command::Private(qq, c), process(), errorBuffer(), outputBuffer(), useDialog(true), canceled(false) { process.setOutputChannelMode(KProcess::SeparateChannels); process.setReadChannel(KProcess::StandardOutput); } DumpCertificateCommand::Private::~Private() { if (dialog && !dialog->isVisible()) { delete dialog; } } DumpCertificateCommand::DumpCertificateCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } DumpCertificateCommand::DumpCertificateCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } DumpCertificateCommand::DumpCertificateCommand(const GpgME::Key &k) : Command(k, new Private(this, nullptr)) { d->init(); } void DumpCertificateCommand::Private::init() { connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); connect(&process, SIGNAL(readyReadStandardError()), q, SLOT(slotProcessReadyReadStandardError())); connect(&process, SIGNAL(readyReadStandardOutput()), q, SLOT(slotProcessReadyReadStandardOutput())); if (!key().isNull()) { process << gpgSmPath() << QStringLiteral("--dump-cert") << QLatin1String(key().primaryFingerprint()); } } DumpCertificateCommand::~DumpCertificateCommand() {} void DumpCertificateCommand::setUseDialog(bool use) { d->useDialog = use; } bool DumpCertificateCommand::useDialog() const { return d->useDialog; } QStringList DumpCertificateCommand::output() const { return d->outputBuffer; } void DumpCertificateCommand::doStart() { const std::vector keys = d->keys(); if (keys.size() != 1 || keys.front().protocol() != GpgME::CMS) { d->finished(); return; } if (d->useDialog) { d->dialog = new DumpCertificateDialog; d->dialog->setAttribute(Qt::WA_DeleteOnClose); d->dialog->setWindowTitle(i18nc("@title:window", "Certificate Dump")); connect(d->dialog, SIGNAL(updateRequested()), this, SLOT(slotUpdateRequested())); connect(d->dialog, SIGNAL(destroyed()), this, SLOT(slotDialogDestroyed())); } d->refreshView(); } void DumpCertificateCommand::Private::refreshView() { if (dialog) { dialog->clear(); } errorBuffer.clear(); outputBuffer.clear(); process.start(); if (process.waitForStarted()) { if (dialog) { dialog->show(); } } else { KMessageBox::error(dialog ? static_cast(dialog) : parentWidgetOrView(), i18n("Unable to start process gpgsm. " "Please check your installation."), i18n("Dump Certificate Error")); finished(); } } void DumpCertificateCommand::doCancel() { d->canceled = true; if (d->process.state() != QProcess::NotRunning) { d->process.terminate(); QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill); } if (d->dialog) { d->dialog->close(); } d->dialog = nullptr; } void DumpCertificateCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status) { if (!canceled) { if (status == QProcess::CrashExit) KMessageBox::error(dialog, i18n("The GpgSM process that tried to dump the certificate " "ended prematurely because of an unexpected error. " "Please check the output of gpgsm --dump-cert %1 for details.", QLatin1String(key().primaryFingerprint())), i18n("Dump Certificate Error")); else if (code) KMessageBox::error(dialog, i18n("An error occurred while trying to dump the certificate. " "The output from GpgSM was:\n%1", errorString()), i18n("Dump Certificate Error")); } if (!useDialog) { slotDialogDestroyed(); } } #undef d #undef q #include "moc_dumpcertificatecommand.cpp" #include "dumpcertificatecommand.moc" diff --git a/src/commands/dumpcrlcachecommand.cpp b/src/commands/dumpcrlcachecommand.cpp index 268ad6827..21af003ac 100644 --- a/src/commands/dumpcrlcachecommand.cpp +++ b/src/commands/dumpcrlcachecommand.cpp @@ -1,351 +1,351 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/dumpcrlcachecommand.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 "dumpcrlcachecommand.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds namespace { class DumpCrlCacheDialog : public QDialog { Q_OBJECT public: explicit DumpCrlCacheDialog(QWidget *parent = nullptr) : QDialog(parent), ui(this), mWithRevocations(false) { readConfig(); } - ~DumpCrlCacheDialog() + ~DumpCrlCacheDialog() override { writeConfig(); } Q_SIGNALS: void updateRequested(); public Q_SLOTS: void append(const QString &line) { ui.logTextWidget.append(line); ui.logTextWidget.ensureCursorVisible(); } void clear() { ui.logTextWidget.clear(); } public: void setWithRevocations (bool value) { mWithRevocations = value; } Q_REQUIRED_RESULT bool withRevocations () { return mWithRevocations; } private: void readConfig() { KConfigGroup dialog(KSharedConfig::openStateConfig(), "DumpCrlCacheDialog"); const QSize size = dialog.readEntry("Size", QSize(600, 400)); if (size.isValid()) { resize(size); } } void writeConfig() { KConfigGroup dialog(KSharedConfig::openStateConfig(), "DumpCrlCacheDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } struct Ui { QTextEdit logTextWidget; QPushButton updateButton, closeButton, revocationsButton; QVBoxLayout vlay; QHBoxLayout hlay; explicit Ui(DumpCrlCacheDialog *q) : logTextWidget(q), updateButton(i18nc("@action:button Update the log text widget", "&Update"), q), closeButton(q), vlay(q), hlay() { KGuiItem::assign(&closeButton, KStandardGuiItem::close()); KDAB_SET_OBJECT_NAME(logTextWidget); KDAB_SET_OBJECT_NAME(updateButton); KDAB_SET_OBJECT_NAME(closeButton); KDAB_SET_OBJECT_NAME(vlay); KDAB_SET_OBJECT_NAME(hlay); logTextWidget.setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); logTextWidget.setReadOnly(true); vlay.addWidget(&logTextWidget, 1); vlay.addLayout(&hlay); revocationsButton.setText(i18n("Show Entries")); hlay.addWidget(&updateButton); hlay.addWidget(&revocationsButton); hlay.addStretch(1); hlay.addWidget(&closeButton); connect(&updateButton, &QAbstractButton::clicked, q, &DumpCrlCacheDialog::updateRequested); connect(&closeButton, &QAbstractButton::clicked, q, &QWidget::close); connect(&revocationsButton, &QAbstractButton::clicked, q, [q, this] () { q->mWithRevocations = true; revocationsButton.setEnabled(false); q->updateRequested(); }); } } ui; bool mWithRevocations; }; } using namespace Kleo; using namespace Kleo::Commands; static QByteArray chomped(QByteArray ba) { while (ba.endsWith('\n') || ba.endsWith('\r')) { ba.chop(1); } return ba; } class DumpCrlCacheCommand::Private : Command::Private { friend class ::Kleo::Commands::DumpCrlCacheCommand; DumpCrlCacheCommand *q_func() const { return static_cast(q); } public: explicit Private(DumpCrlCacheCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QString errorString() const { return QString::fromLocal8Bit(errorBuffer); } private: void init(); void refreshView(); private: void slotProcessFinished(int, QProcess::ExitStatus); void slotProcessReadyReadStandardOutput() { static int count; while (process.canReadLine()) { if (!dialog) { break; } const QByteArray line = chomped(process.readLine()); if (!line.size()) { continue; } if (!dialog->withRevocations() && line.contains("reasons")) { count++; continue; } else if (count) { dialog->append (QLatin1Char(' ') + i18nc("Count of revocations in a CRL", "Entries:") + QStringLiteral("\t\t%1\n").arg(count)); count = 0; } dialog->append(stringFromGpgOutput(line)); } } void slotProcessReadyReadStandardError() { errorBuffer += process.readAllStandardError(); } void slotUpdateRequested() { if (process.state() == QProcess::NotRunning) { refreshView(); } } void slotDialogDestroyed() { dialog = nullptr; if (process.state() != QProcess::NotRunning) { q->cancel(); } else { finished(); } } private: DumpCrlCacheDialog *dialog; KProcess process; QByteArray errorBuffer; bool canceled; }; DumpCrlCacheCommand::Private *DumpCrlCacheCommand::d_func() { return static_cast(d.get()); } const DumpCrlCacheCommand::Private *DumpCrlCacheCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() DumpCrlCacheCommand::Private::Private(DumpCrlCacheCommand *qq, KeyListController *c) : Command::Private(qq, c), dialog(nullptr), process(), errorBuffer(), canceled(false) { process.setOutputChannelMode(KProcess::SeparateChannels); process.setReadChannel(KProcess::StandardOutput); process << gpgSmPath() << QStringLiteral("--call-dirmngr") << QStringLiteral("listcrls"); } DumpCrlCacheCommand::Private::~Private() { if (dialog && !dialog->isVisible()) { delete dialog; } } DumpCrlCacheCommand::DumpCrlCacheCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } DumpCrlCacheCommand::DumpCrlCacheCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void DumpCrlCacheCommand::Private::init() { connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); connect(&process, SIGNAL(readyReadStandardError()), q, SLOT(slotProcessReadyReadStandardError())); connect(&process, SIGNAL(readyReadStandardOutput()), q, SLOT(slotProcessReadyReadStandardOutput())); } DumpCrlCacheCommand::~DumpCrlCacheCommand() {} void DumpCrlCacheCommand::doStart() { d->dialog = new DumpCrlCacheDialog; d->dialog->setAttribute(Qt::WA_DeleteOnClose); d->dialog->setWindowTitle(i18nc("@title:window", "CRL Cache Dump")); connect(d->dialog, SIGNAL(updateRequested()), this, SLOT(slotUpdateRequested())); connect(d->dialog, SIGNAL(destroyed()), this, SLOT(slotDialogDestroyed())); d->refreshView(); } void DumpCrlCacheCommand::Private::refreshView() { dialog->clear(); process.start(); if (process.waitForStarted()) { dialog->show(); } else { KMessageBox::error(dialog ? static_cast(dialog) : parentWidgetOrView(), i18n("Unable to start process gpgsm. " "Please check your installation."), i18n("Dump CRL Cache Error")); finished(); } } void DumpCrlCacheCommand::doCancel() { d->canceled = true; if (d->process.state() != QProcess::NotRunning) { d->process.terminate(); QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill); } if (d->dialog) { d->dialog->close(); } d->dialog = nullptr; } void DumpCrlCacheCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status) { if (!canceled) { if (status == QProcess::CrashExit) KMessageBox::error(dialog, i18n("The GpgSM process that tried to dump the CRL cache " "ended prematurely because of an unexpected error. " "Please check the output of gpgsm --call-dirmngr listcrls for details."), i18n("Dump CRL Cache Error")); else if (code) KMessageBox::error(dialog, i18n("An error occurred while trying to dump the CRL cache. " "The output from GpgSM was:\n%1", errorString()), i18n("Dump CRL Cache Error")); } } #undef d #undef q #include "moc_dumpcrlcachecommand.cpp" #include "dumpcrlcachecommand.moc" diff --git a/src/commands/encryptclipboardcommand.cpp b/src/commands/encryptclipboardcommand.cpp index 254582a9b..49d2e936f 100644 --- a/src/commands/encryptclipboardcommand.cpp +++ b/src/commands/encryptclipboardcommand.cpp @@ -1,174 +1,174 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/encryptclipboardcommand.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 "encryptclipboardcommand.h" #ifndef QT_NO_CLIPBOARD #include "command_p.h" #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class EncryptClipboardCommand::Private : public Command::Private { friend class ::Kleo::Commands::EncryptClipboardCommand; EncryptClipboardCommand *q_func() const { return static_cast(q); } public: explicit Private(EncryptClipboardCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotRecipientsResolved(); void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: std::shared_ptr shared_qq; std::shared_ptr input; EncryptEMailController controller; }; EncryptClipboardCommand::Private *EncryptClipboardCommand::d_func() { return static_cast(d.get()); } const EncryptClipboardCommand::Private *EncryptClipboardCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() EncryptClipboardCommand::Private::Private(EncryptClipboardCommand *qq, KeyListController *c) : Command::Private(qq, c), shared_qq(qq, [](EncryptClipboardCommand*){}), input(), controller(EncryptEMailController::ClipboardMode) { } EncryptClipboardCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } EncryptClipboardCommand::EncryptClipboardCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } EncryptClipboardCommand::EncryptClipboardCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void EncryptClipboardCommand::Private::init() { controller.setExecutionContext(shared_qq); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } EncryptClipboardCommand::~EncryptClipboardCommand() { qCDebug(KLEOPATRA_LOG); } // static bool EncryptClipboardCommand::canEncryptCurrentClipboard() { if (const QClipboard *clip = QApplication::clipboard()) if (const QMimeData *mime = clip->mimeData()) { return mime->hasText(); } return false; } void EncryptClipboardCommand::doStart() { try { // snapshot clipboard content here, in case it's being changed... d->input = Input::createFromClipboard(); connect(&d->controller, SIGNAL(recipientsResolved()), this, SLOT(slotRecipientsResolved())); d->controller.startResolveRecipients(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Encrypt Clipboard Error")); d->finished(); } } void EncryptClipboardCommand::Private::slotRecipientsResolved() { try { controller.setInputAndOutput(input, Output::createFromClipboard()); input.reset(); // no longer needed, so don't keep a reference controller.start(); } catch (const std::exception &e) { information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Encrypt Clipboard Error")); finished(); } } void EncryptClipboardCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } #undef d #undef q #include "moc_encryptclipboardcommand.cpp" #endif // QT_NO_CLIPBOARD diff --git a/src/commands/exportcertificatecommand.cpp b/src/commands/exportcertificatecommand.cpp index 6ddd91bd5..0538477a3 100644 --- a/src/commands/exportcertificatecommand.cpp +++ b/src/commands/exportcertificatecommand.cpp @@ -1,360 +1,360 @@ /* -*- mode: c++; c-basic-offset:4 -*- exportcertificatecommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2021 g10 Code GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "exportcertificatecommand.h" #include "fileoperationspreferences.h" #include "command_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; using namespace GpgME; using namespace QGpgME; class ExportCertificateCommand::Private : public Command::Private { friend class ::ExportCertificateCommand; ExportCertificateCommand *q_func() const { return static_cast(q); } public: explicit Private(ExportCertificateCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void startExportJob(GpgME::Protocol protocol, const std::vector &keys); void cancelJobs(); void exportResult(const GpgME::Error &, const QByteArray &); void showError(const GpgME::Error &error); bool requestFileNames(GpgME::Protocol prot); void finishedIfLastJob(); private: QMap fileNames; uint jobsPending = 0; QMap outFileForSender; QPointer cmsJob; QPointer pgpJob; }; ExportCertificateCommand::Private *ExportCertificateCommand::d_func() { return static_cast(d.get()); } const ExportCertificateCommand::Private *ExportCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ExportCertificateCommand::Private::Private(ExportCertificateCommand *qq, KeyListController *c) : Command::Private(qq, c) { } ExportCertificateCommand::Private::~Private() {} ExportCertificateCommand::ExportCertificateCommand(KeyListController *p) : Command(new Private(this, p)) { } ExportCertificateCommand::ExportCertificateCommand(QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { } ExportCertificateCommand::ExportCertificateCommand(const Key &key) : Command(key, new Private(this, nullptr)) { } ExportCertificateCommand::~ExportCertificateCommand() {} void ExportCertificateCommand::setOpenPGPFileName(const QString &fileName) { if (!d->jobsPending) { d->fileNames[OpenPGP] = fileName; } } QString ExportCertificateCommand::openPGPFileName() const { return d->fileNames[OpenPGP]; } void ExportCertificateCommand::setX509FileName(const QString &fileName) { if (!d->jobsPending) { d->fileNames[CMS] = fileName; } } QString ExportCertificateCommand::x509FileName() const { return d->fileNames[CMS]; } void ExportCertificateCommand::doStart() { std::vector keys = d->keys(); if (keys.empty()) { return; } const auto firstCms = std::partition(keys.begin(), keys.end(), [](const GpgME::Key &key) { return key.protocol() != GpgME::CMS; }); std::vector openpgp, cms; std::copy(keys.begin(), firstCms, std::back_inserter(openpgp)); std::copy(firstCms, keys.end(), std::back_inserter(cms)); Q_ASSERT(!openpgp.empty() || !cms.empty()); const bool haveBoth = !cms.empty() && !openpgp.empty(); const GpgME::Protocol prot = haveBoth ? UnknownProtocol : (!cms.empty() ? CMS : OpenPGP); if (!d->requestFileNames(prot)) { Q_EMIT canceled(); d->finished(); } else { if (!openpgp.empty()) { d->startExportJob(GpgME::OpenPGP, openpgp); } if (!cms.empty()) { d->startExportJob(GpgME::CMS, cms); } } } bool ExportCertificateCommand::Private::requestFileNames(GpgME::Protocol protocol) { if (protocol == UnknownProtocol) { if (!fileNames[GpgME::OpenPGP].isEmpty() && !fileNames[GpgME::CMS].isEmpty()) { return true; } /* Unkown protocol ask for first PGP Export file name */ if (fileNames[GpgME::OpenPGP].isEmpty() && !requestFileNames(GpgME::OpenPGP)) { return false; } /* And then for CMS */ return requestFileNames(GpgME::CMS); } if (!fileNames[protocol].isEmpty()) { return true; } KConfigGroup config(KSharedConfig::openConfig(), "ExportDialog"); const auto lastDir = config.readEntry("LastDirectory", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)); QString proposedFileName = lastDir + QLatin1Char('/'); if (keys().size() == 1) { const bool usePGPFileExt = FileOperationsPreferences().usePGPFileExt(); const auto key = keys().front(); auto name = Formatting::prettyName(key); if (name.isEmpty()) { name = Formatting::prettyEMail(key); } /* Not translated so it's better to use in tutorials etc. */ proposedFileName += QStringLiteral("%1_%2_public.%3").arg(name).arg( Formatting::prettyKeyID(key.shortKeyID())).arg( QString::fromLatin1(outputFileExtension(protocol == OpenPGP ? Class::OpenPGP | Class::Ascii | Class::Certificate : Class::CMS | Class::Ascii | Class::Certificate, usePGPFileExt))); } if (protocol == GpgME::CMS) { if (!fileNames[GpgME::OpenPGP].isEmpty()) { /* If the user has already selected a PGP file name then use that as basis * for a proposal for the S/MIME file. */ proposedFileName = fileNames[GpgME::OpenPGP]; proposedFileName.replace(QRegExp(QStringLiteral(".asc$")), QStringLiteral(".pem")); proposedFileName.replace(QRegExp(QStringLiteral(".gpg$")), QStringLiteral(".der")); proposedFileName.replace(QRegExp(QStringLiteral(".pgp$")), QStringLiteral(".der")); } } if (proposedFileName.isEmpty()) { proposedFileName = lastDir; proposedFileName += i18nc("A generic filename for exported certificates", "certificates"); proposedFileName += protocol == GpgME::OpenPGP ? QStringLiteral(".asc") : QStringLiteral(".pem"); } auto fname = FileDialog::getSaveFileNameEx(parentWidgetOrView(), i18nc("1 is protocol", "Export %1 Certificates", Formatting::displayName(protocol)), QStringLiteral("imp"), proposedFileName, protocol == GpgME::OpenPGP ? i18n("OpenPGP Certificates") + QLatin1String(" (*.asc *.gpg *.pgp)") : i18n("S/MIME Certificates") + QLatin1String(" (*.pem *.der)")); if (!fname.isEmpty() && protocol == GpgME::CMS && fileNames[GpgME::OpenPGP] == fname) { KMessageBox::error(parentWidgetOrView(), i18n("You have to select different filenames for different protocols."), i18n("Export Error")); return false; } const QFileInfo fi(fname); if (fi.suffix().isEmpty()) { fname += protocol == GpgME::OpenPGP ? QStringLiteral(".asc") : QStringLiteral(".pem"); } fileNames[protocol] = fname; config.writeEntry("LastDirectory", fi.absolutePath()); return !fname.isEmpty(); } void ExportCertificateCommand::Private::startExportJob(GpgME::Protocol protocol, const std::vector &keys) { Q_ASSERT(protocol != GpgME::UnknownProtocol); const QGpgME::Protocol *const backend = (protocol == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); Q_ASSERT(backend); const QString fileName = fileNames[protocol]; const bool binary = protocol == GpgME::OpenPGP ? fileName.endsWith(QLatin1String(".gpg"), Qt::CaseInsensitive) || fileName.endsWith(QLatin1String(".pgp"), Qt::CaseInsensitive) : fileName.endsWith(QLatin1String(".der"), Qt::CaseInsensitive); std::unique_ptr job(backend->publicKeyExportJob(!binary)); Q_ASSERT(job.get()); connect(job.get(), SIGNAL(result(GpgME::Error,QByteArray)), q, SLOT(exportResult(GpgME::Error,QByteArray))); connect(job.get(), &Job::progress, q, &Command::progress); QStringList fingerprints; fingerprints.reserve(keys.size()); for (const Key &i : keys) { fingerprints << QLatin1String(i.primaryFingerprint()); } const GpgME::Error err = job->start(fingerprints); if (err) { showError(err); finished(); return; } Q_EMIT q->info(i18n("Exporting certificates...")); ++jobsPending; const QPointer exportJob(job.release()); outFileForSender[exportJob.data()] = fileName; (protocol == CMS ? cmsJob : pgpJob) = exportJob; } void ExportCertificateCommand::Private::showError(const GpgME::Error &err) { Q_ASSERT(err); const QString msg = i18n("

An error occurred while trying to export " "the certificate:

" "

%1

", QString::fromLocal8Bit(err.asString())); error(msg, i18n("Certificate Export Failed")); } void ExportCertificateCommand::doCancel() { d->cancelJobs(); } void ExportCertificateCommand::Private::finishedIfLastJob() { if (jobsPending <= 0) { finished(); } } static bool write_complete(QIODevice &iod, const QByteArray &data) { qint64 total = 0; qint64 toWrite = data.size(); while (total < toWrite) { const qint64 written = iod.write(data.data() + total, toWrite); if (written < 0) { return false; } total += written; toWrite -= written; } return true; } void ExportCertificateCommand::Private::exportResult(const GpgME::Error &err, const QByteArray &data) { Q_ASSERT(jobsPending > 0); --jobsPending; Q_ASSERT(outFileForSender.contains(q->sender())); const QString outFile = outFileForSender[q->sender()]; if (err) { showError(err); finishedIfLastJob(); return; } QSaveFile savefile(outFile); //TODO: use KIO const QString writeErrorMsg = i18n("Could not write to file %1.", outFile); const QString errorCaption = i18n("Certificate Export Failed"); if (!savefile.open(QIODevice::WriteOnly)) { error(writeErrorMsg, errorCaption); finishedIfLastJob(); return; } if (!write_complete(savefile, data) || !savefile.commit()) { error(writeErrorMsg, errorCaption); } finishedIfLastJob(); } void ExportCertificateCommand::Private::cancelJobs() { if (cmsJob) { cmsJob->slotCancel(); } if (pgpJob) { pgpJob->slotCancel(); } } #undef d #undef q #include "moc_exportcertificatecommand.cpp" diff --git a/src/commands/gnupgprocesscommand.cpp b/src/commands/gnupgprocesscommand.cpp index 879a157b2..c5ac41e90 100644 --- a/src/commands/gnupgprocesscommand.cpp +++ b/src/commands/gnupgprocesscommand.cpp @@ -1,381 +1,381 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/gnupgprocesscommand.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 "gnupgprocesscommand.h" #include "command_p.h" #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds using namespace Kleo; using namespace Kleo::Commands; namespace { class OutputDialog : public QDialog { Q_OBJECT public: explicit OutputDialog(QWidget *parent = nullptr) : QDialog(parent), vlay(this), logTextWidget(this), buttonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Close, Qt::Horizontal, this) { KDAB_SET_OBJECT_NAME(vlay); KDAB_SET_OBJECT_NAME(logTextWidget); KDAB_SET_OBJECT_NAME(buttonBox); logTextWidget.setReadOnly(true); vlay.addWidget(&logTextWidget, 1); vlay.addWidget(&buttonBox); connect(closeButton(), &QAbstractButton::clicked, this, &QWidget::close); connect(cancelButton(), &QAbstractButton::clicked, this, &OutputDialog::slotCancelClicked); resize(600, 500); } Q_SIGNALS: void cancelRequested(); public Q_SLOTS: void message(const QString &s) { logTextWidget.append(s); logTextWidget.ensureCursorVisible(); } void setComplete(bool complete) { cancelButton()->setVisible(!complete); } private Q_SLOTS: void slotCancelClicked() { cancelButton()->hide(); Q_EMIT cancelRequested(); } private: QAbstractButton *closeButton() const { return buttonBox.button(QDialogButtonBox::Close); } QAbstractButton *cancelButton() const { return buttonBox.button(QDialogButtonBox::Cancel); } private: QVBoxLayout vlay; QTextEdit logTextWidget; QDialogButtonBox buttonBox; }; } class GnuPGProcessCommand::Private : Command::Private { friend class ::Kleo::Commands::GnuPGProcessCommand; GnuPGProcessCommand *q_func() const { return static_cast(q); } public: explicit Private(GnuPGProcessCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; private: void init(); void ensureDialogCreated() { if (!showsOutputWindow) { return; } if (!dialog) { dialog = new OutputDialog; dialog->setAttribute(Qt::WA_DeleteOnClose); applyWindowID(dialog); connect(dialog.data(), &OutputDialog::cancelRequested, q, &Command::cancel); dialog->setWindowTitle(i18nc("@title:window", "Subprocess Diagnostics")); } } void ensureDialogVisible() { if (!showsOutputWindow) { return; } ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } #ifdef Q_OS_WIN KWindowSystem::forceActiveWindow(dialog->winId()); #endif } void message(const QString &msg) { if (dialog) { dialog->message(msg); } else { qCDebug(KLEOPATRA_LOG) << msg; } } private: void slotProcessFinished(int, QProcess::ExitStatus); void slotProcessReadyReadStandardError(); private: QProcess process; QPointer dialog; QStringList arguments; QByteArray errorBuffer; bool ignoresSuccessOrFailure; bool showsOutputWindow; bool canceled; }; GnuPGProcessCommand::Private *GnuPGProcessCommand::d_func() { return static_cast(d.get()); } const GnuPGProcessCommand::Private *GnuPGProcessCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() GnuPGProcessCommand::Private::Private(GnuPGProcessCommand *qq, KeyListController *c) : Command::Private(qq, c), process(), dialog(), errorBuffer(), ignoresSuccessOrFailure(false), showsOutputWindow(false), canceled(false) { process.setReadChannel(QProcess::StandardError); } GnuPGProcessCommand::Private::~Private() {} GnuPGProcessCommand::GnuPGProcessCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } GnuPGProcessCommand::GnuPGProcessCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } GnuPGProcessCommand::GnuPGProcessCommand(const GpgME::Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } void GnuPGProcessCommand::Private::init() { connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); connect(&process, SIGNAL(readyReadStandardError()), q, SLOT(slotProcessReadyReadStandardError())); } GnuPGProcessCommand::~GnuPGProcessCommand() {} QDialog *GnuPGProcessCommand::dialog() const { return d->dialog; } bool GnuPGProcessCommand::preStartHook(QWidget *) const { return true; } void GnuPGProcessCommand::postSuccessHook(QWidget *) { } void GnuPGProcessCommand::doStart() { if (!preStartHook(d->parentWidgetOrView())) { d->finished(); return; } d->arguments = arguments(); d->process.setProgram(d->arguments.takeFirst()); d->process.setArguments(d->arguments); // Historically code using this expects arguments first to be the program. d->arguments.prepend(d->process.program()); d->process.start(); if (!d->process.waitForStarted()) { d->error(i18n("Unable to start process %1. " "Please check your installation.", d->arguments[0]), errorCaption()); d->finished(); } else { d->ensureDialogVisible(); d->message(i18n("Starting %1...", d->arguments.join(QLatin1Char(' ')))); } } void GnuPGProcessCommand::doCancel() { d->canceled = true; if (d->process.state() != QProcess::NotRunning) { d->process.terminate(); QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill); } } void GnuPGProcessCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status) { if (!canceled) { if (status == QProcess::CrashExit) { const QString msg = q->crashExitMessage(arguments); if (!msg.isEmpty()) { error(msg, q->errorCaption()); } } else if (ignoresSuccessOrFailure) { if (dialog) { message(i18n("Process finished")); } else { ; } } else if (code) { const QString msg = q->errorExitMessage(arguments); if (!msg.isEmpty()) { error(q->errorExitMessage(arguments), q->errorCaption()); } } else { q->postSuccessHook(parentWidgetOrView()); const QString successMessage = q->successMessage(arguments); if (!successMessage.isNull()) { if (dialog) { message(successMessage); } else { information(successMessage, q->successCaption()); } } } } if (dialog) { dialog->setComplete(true); } finished(); } void GnuPGProcessCommand::Private::slotProcessReadyReadStandardError() { auto ba = process.readAllStandardError(); errorBuffer += ba; while (ba.endsWith('\n') || ba.endsWith('\r')) { ba.chop(1); } message(Kleo::stringFromGpgOutput(ba)); } QString GnuPGProcessCommand::errorString() const { return Kleo::stringFromGpgOutput(d->errorBuffer); } void GnuPGProcessCommand::setIgnoresSuccessOrFailure(bool ignores) { d->ignoresSuccessOrFailure = ignores; } bool GnuPGProcessCommand::ignoresSuccessOrFailure() const { return d->ignoresSuccessOrFailure; } void GnuPGProcessCommand::setShowsOutputWindow(bool show) { if (show == d->showsOutputWindow) { return; } d->showsOutputWindow = show; if (show) { d->ensureDialogCreated(); } else { if (d->dialog) { d->dialog->deleteLater(); } d->dialog = nullptr; } } bool GnuPGProcessCommand::showsOutputWindow() const { return d->showsOutputWindow; } QProcess *GnuPGProcessCommand::process() { return &d->process; } QString GnuPGProcessCommand::successCaption() const { return QString(); } QString GnuPGProcessCommand::successMessage(const QStringList &args) const { Q_UNUSED(args) return QString(); } #undef d #undef q #include "moc_gnupgprocesscommand.cpp" #include "gnupgprocesscommand.moc" diff --git a/src/commands/importcertificatefromclipboardcommand.cpp b/src/commands/importcertificatefromclipboardcommand.cpp index a38b9e922..773d083c7 100644 --- a/src/commands/importcertificatefromclipboardcommand.cpp +++ b/src/commands/importcertificatefromclipboardcommand.cpp @@ -1,130 +1,130 @@ /* -*- mode: c++; c-basic-offset:4 -*- importcertificatefromclipboardcommand.cpp This clipboard is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "importcertificatefromclipboardcommand.h" #ifndef QT_NO_CLIPBOARD #include "importcertificatescommand_p.h" #include #include #include #include #include #include #include using namespace GpgME; using namespace Kleo; class ImportCertificateFromClipboardCommand::Private : public ImportCertificatesCommand::Private { friend class ::ImportCertificateFromClipboardCommand; ImportCertificateFromClipboardCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromClipboardCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; bool ensureHaveClipboard(); private: QByteArray input; }; ImportCertificateFromClipboardCommand::Private *ImportCertificateFromClipboardCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromClipboardCommand::Private *ImportCertificateFromClipboardCommand::d_func() const { return static_cast(d.get()); } ImportCertificateFromClipboardCommand::Private::Private(ImportCertificateFromClipboardCommand *qq, KeyListController *c) : ImportCertificatesCommand::Private(qq, c) { } ImportCertificateFromClipboardCommand::Private::~Private() {} // static bool ImportCertificateFromClipboardCommand::canImportCurrentClipboard() { if (const QClipboard *clip = QApplication::clipboard()) if (const QMimeData *mime = clip->mimeData()) return mime->hasText() && mayBeAnyCertStoreType(classifyContent(mime->text().toUtf8())); return false; } #define d d_func() #define q q_func() ImportCertificateFromClipboardCommand::ImportCertificateFromClipboardCommand(KeyListController *p) : ImportCertificatesCommand(new Private(this, p)) { } ImportCertificateFromClipboardCommand::ImportCertificateFromClipboardCommand(QAbstractItemView *v, KeyListController *p) : ImportCertificatesCommand(v, new Private(this, p)) { } ImportCertificateFromClipboardCommand::~ImportCertificateFromClipboardCommand() {} void ImportCertificateFromClipboardCommand::doStart() { if (!d->ensureHaveClipboard()) { Q_EMIT canceled(); d->finished(); return; } d->setWaitForMoreJobs(true); const unsigned int classification = classifyContent(d->input); if (!mayBeAnyCertStoreType(classification)) { d->error(i18n("Clipboard contents do not look like a certificate."), i18n("Certificate Import Failed")); } else { const GpgME::Protocol protocol = findProtocol(classification); if (protocol == GpgME::UnknownProtocol) { d->error(i18n("Could not determine certificate type of clipboard contents."), i18n("Certificate Import Failed")); } else { d->startImport(protocol, d->input, i18n("Clipboard")); } } d->setWaitForMoreJobs(false); } bool ImportCertificateFromClipboardCommand::Private::ensureHaveClipboard() { if (input.isEmpty()) if (const QClipboard *cb = qApp->clipboard()) { input = cb->text().toUtf8(); } return !input.isEmpty(); } #undef d #undef q #endif // QT_NO_CLIPBOARD diff --git a/src/commands/importcertificatefromdatacommand.cpp b/src/commands/importcertificatefromdatacommand.cpp index 08c494dbb..f7278cd96 100644 --- a/src/commands/importcertificatefromdatacommand.cpp +++ b/src/commands/importcertificatefromdatacommand.cpp @@ -1,78 +1,78 @@ /* -*- mode: c++; c-basic-offset:4 -*- importcertificatefromdatacommand.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 "importcertificatefromdatacommand.h" #include "importcertificatescommand_p.h" #include #include using namespace GpgME; using namespace Kleo; using namespace QGpgME; class ImportCertificateFromDataCommand::Private : public ImportCertificatesCommand::Private { friend class ::ImportCertificateFromDataCommand; ImportCertificateFromDataCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromDataCommand *qq, const QByteArray &data, GpgME::Protocol proto, const QString &id); - ~Private(); + ~Private() override; private: QByteArray mData; GpgME::Protocol mProto; QString mId; }; ImportCertificateFromDataCommand::Private *ImportCertificateFromDataCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromDataCommand::Private *ImportCertificateFromDataCommand::d_func() const { return static_cast(d.get()); } ImportCertificateFromDataCommand::Private::Private(ImportCertificateFromDataCommand *qq, const QByteArray &data, GpgME::Protocol proto, const QString &id) : ImportCertificatesCommand::Private(qq, nullptr), mData(data), mProto(proto), mId(id) { } ImportCertificateFromDataCommand::Private::~Private() {} #define d d_func() #define q q_func() ImportCertificateFromDataCommand::ImportCertificateFromDataCommand(const QByteArray &data, GpgME::Protocol proto, const QString &id) : ImportCertificatesCommand(new Private(this, data, proto, id)) { } ImportCertificateFromDataCommand::~ImportCertificateFromDataCommand() {} void ImportCertificateFromDataCommand::doStart() { d->startImport(d->mProto, d->mData, d->mId.isEmpty() ? i18n("Notepad") : d->mId); } #undef d #undef q diff --git a/src/commands/importcertificatefromfilecommand.cpp b/src/commands/importcertificatefromfilecommand.cpp index 7c26ba294..d823e050c 100644 --- a/src/commands/importcertificatefromfilecommand.cpp +++ b/src/commands/importcertificatefromfilecommand.cpp @@ -1,173 +1,173 @@ /* -*- mode: c++; c-basic-offset:4 -*- importcertificatefromfilecommand.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 "importcertificatefromfilecommand.h" #include "importcertificatescommand_p.h" #include "utils/filedialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GpgME; using namespace Kleo; using namespace QGpgME; class ImportCertificateFromFileCommand::Private : public ImportCertificatesCommand::Private { friend class ::ImportCertificateFromFileCommand; ImportCertificateFromFileCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromFileCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; bool ensureHaveFile(); private: QStringList files; }; ImportCertificateFromFileCommand::Private *ImportCertificateFromFileCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromFileCommand::Private *ImportCertificateFromFileCommand::d_func() const { return static_cast(d.get()); } ImportCertificateFromFileCommand::Private::Private(ImportCertificateFromFileCommand *qq, KeyListController *c) : ImportCertificatesCommand::Private(qq, c), files() { } ImportCertificateFromFileCommand::Private::~Private() {} #define d d_func() #define q q_func() ImportCertificateFromFileCommand::ImportCertificateFromFileCommand() : ImportCertificatesCommand(new Private(this, nullptr)) { } ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(KeyListController *p) : ImportCertificatesCommand(new Private(this, p)) { } ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(QAbstractItemView *v, KeyListController *p) : ImportCertificatesCommand(v, new Private(this, p)) { } ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(const QStringList &files, KeyListController *p) : ImportCertificatesCommand(new Private(this, p)) { d->files = files; } ImportCertificateFromFileCommand::ImportCertificateFromFileCommand(const QStringList &files, QAbstractItemView *v, KeyListController *p) : ImportCertificatesCommand(v, new Private(this, p)) { d->files = files; } ImportCertificateFromFileCommand::~ImportCertificateFromFileCommand() {} void ImportCertificateFromFileCommand::setFiles(const QStringList &files) { d->files = files; } void ImportCertificateFromFileCommand::doStart() { if (!d->ensureHaveFile()) { Q_EMIT canceled(); d->finished(); return; } //TODO: use KIO here d->setWaitForMoreJobs(true); for (const QString &fn : std::as_const(d->files)) { QFile in(fn); if (!in.open(QIODevice::ReadOnly)) { d->error(i18n("Could not open file %1 for reading: %2", in.fileName(), in.errorString()), i18n("Certificate Import Failed")); d->importResult(ImportResult(), fn); continue; } const GpgME::Protocol protocol = findProtocol(fn); if (protocol == GpgME::UnknownProtocol) { //TODO: might use exceptions here d->error(i18n("Could not determine certificate type of %1.", in.fileName()), i18n("Certificate Import Failed")); d->importResult(ImportResult(), fn); continue; } d->startImport(protocol, in.readAll(), fn); } d->setWaitForMoreJobs(false); } static QStringList get_file_name(QWidget *parent) { const QString certificateFilter = i18n("Certificates") + QLatin1String(" (*.asc *.cer *.cert *.crt *.der *.pem *.gpg *.p7c *.p12 *.pfx *.pgp)"); const QString anyFilesFilter = i18n("Any files") + QLatin1String(" (*)"); QString previousDir; if (const KSharedConfig::Ptr config = KSharedConfig::openConfig()) { const KConfigGroup group(config, "Import Certificate"); previousDir = group.readPathEntry("last-open-file-directory", QDir::homePath()); } const QStringList files = Kleo::FileDialog::getOpenFileNames(parent, i18n("Select Certificate File"), previousDir, certificateFilter + QLatin1String(";;") + anyFilesFilter); if (!files.empty()) if (const KSharedConfig::Ptr config = KSharedConfig::openConfig()) { KConfigGroup group(config, "Import Certificate"); group.writePathEntry("last-open-file-directory", QFileInfo(files.front()).path()); } return files; } bool ImportCertificateFromFileCommand::Private::ensureHaveFile() { if (files.empty()) { files = get_file_name(parentWidgetOrView()); } return !files.empty(); } #undef d #undef q diff --git a/src/commands/importcertificatefrompivcardcommand.cpp b/src/commands/importcertificatefrompivcardcommand.cpp index 994eb191f..d4ab5653d 100644 --- a/src/commands/importcertificatefrompivcardcommand.cpp +++ b/src/commands/importcertificatefrompivcardcommand.cpp @@ -1,136 +1,136 @@ /* commands/importcertificatefrompivcardcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "importcertificatefrompivcardcommand.h" #include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "commands/importcertificatefromdatacommand.h" #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; class ImportCertificateFromPIVCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::ImportCertificateFromPIVCardCommand; ImportCertificateFromPIVCardCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificateFromPIVCardCommand *qq, const std::string &slot, const std::string &serialno); - ~Private(); + ~Private() override; private: void start(); void importFinished(); void importCanceled(); private: std::string cardSlot; bool hasBeenCanceled = false; }; ImportCertificateFromPIVCardCommand::Private *ImportCertificateFromPIVCardCommand::d_func() { return static_cast(d.get()); } const ImportCertificateFromPIVCardCommand::Private *ImportCertificateFromPIVCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() ImportCertificateFromPIVCardCommand::Private::Private(ImportCertificateFromPIVCardCommand *qq, const std::string &slot, const std::string &serialno) : CardCommand::Private(qq, serialno, nullptr) , cardSlot(slot) { } ImportCertificateFromPIVCardCommand::Private::~Private() { } void ImportCertificateFromPIVCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::Private::start()"; const auto pivCard = ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const std::string certificateData = pivCard->certificateData(cardSlot); if (certificateData.empty()) { error(i18n("Sorry! No certificate to import from this card slot was found.")); finished(); return; } auto cmd = new ImportCertificateFromDataCommand(QByteArray::fromStdString(certificateData), GpgME::CMS, i18n("Card Certificate")); connect(cmd, &ImportCertificateFromDataCommand::finished, q, [this]() { importFinished(); }); connect(cmd, &ImportCertificateFromDataCommand::canceled, q, [this]() { importCanceled(); }); cmd->start(); } void ImportCertificateFromPIVCardCommand::Private::importFinished() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::importFinished()"; if (!hasBeenCanceled) { finished(); } } void ImportCertificateFromPIVCardCommand::Private::importCanceled() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::importCanceled()"; hasBeenCanceled = true; canceled(); } ImportCertificateFromPIVCardCommand::ImportCertificateFromPIVCardCommand(const std::string& cardSlot, const std::string &serialno) : CardCommand(new Private(this, cardSlot, serialno)) { } ImportCertificateFromPIVCardCommand::~ImportCertificateFromPIVCardCommand() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::~ImportCertificateFromPIVCardCommand()"; } void ImportCertificateFromPIVCardCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "ImportCertificateFromPIVCardCommand::doStart()"; d->start(); } void ImportCertificateFromPIVCardCommand::doCancel() { } #undef q_func #undef d_func diff --git a/src/commands/importcertificatescommand_p.h b/src/commands/importcertificatescommand_p.h index 5b1073e10..7ac738abd 100644 --- a/src/commands/importcertificatescommand_p.h +++ b/src/commands/importcertificatescommand_p.h @@ -1,92 +1,92 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/importcertificatescommand_p.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007, 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "command_p.h" #include "importcertificatescommand.h" #include #include #include namespace GpgME { class ImportResult; class Import; class KeyListResult; class Error; } namespace QGpgME { class AbstractImportJob; } class QByteArray; class Kleo::ImportCertificatesCommand::Private : public Command::Private { friend class ::Kleo::ImportCertificatesCommand; Kleo::ImportCertificatesCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCertificatesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void setWaitForMoreJobs(bool waiting); void startImport(GpgME::Protocol proto, const QByteArray &data, const QString &id = QString()); void startImport(GpgME::Protocol proto, const std::vector &keys, const QString &id = QString()); void importResult(const GpgME::ImportResult &); void importResult(const GpgME::ImportResult &, const QString &); void showError(QWidget *parent, const GpgME::Error &error, const QString &id = QString()); void showError(const GpgME::Error &error, const QString &id = QString()); void showDetails(QWidget *parent, const std::vector &results, const QStringList &ids); void showDetails(const std::vector &results, const QStringList &ids); void setImportResultProxyModel(const std::vector &results, const QStringList &ids); bool showPleaseCertify(const GpgME::Import &imp); void keyListDone(const GpgME::KeyListResult &result, const std::vector &keys, const QString &, const GpgME::Error&); private: void handleExternalCMSImports(); void tryToFinish(); private: bool waitForMoreJobs; bool containedExternalCMSCerts; std::vector nonWorkingProtocols; std::map idsByJob; std::vector jobs; std::vector results; QStringList ids; }; inline Kleo::ImportCertificatesCommand::Private *Kleo::ImportCertificatesCommand::d_func() { return static_cast(d.get()); } inline const Kleo::ImportCertificatesCommand::Private *Kleo::ImportCertificatesCommand::d_func() const { return static_cast(d.get()); } inline Kleo::ImportCertificatesCommand::ImportCertificatesCommand(Private *pp) : Command(pp) {} inline Kleo::ImportCertificatesCommand::ImportCertificatesCommand(QAbstractItemView *v, Private *pp) : Command(v, pp) {} diff --git a/src/commands/importcrlcommand.cpp b/src/commands/importcrlcommand.cpp index 0b69b28c7..e2170f5aa 100644 --- a/src/commands/importcrlcommand.cpp +++ b/src/commands/importcrlcommand.cpp @@ -1,216 +1,216 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/importcrlcommand.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 "importcrlcommand.h" #include "command_p.h" #include #include #include #include #include #include #include static const int PROCESS_TERMINATE_TIMEOUT = 5000; // milliseconds using namespace Kleo; using namespace Kleo::Commands; class ImportCrlCommand::Private : Command::Private { friend class ::Kleo::Commands::ImportCrlCommand; ImportCrlCommand *q_func() const { return static_cast(q); } public: explicit Private(ImportCrlCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; Q_REQUIRED_RESULT QString errorString() const { return stringFromGpgOutput(errorBuffer); } private: void init(); #ifndef QT_NO_FILEDIALOG QStringList getFileNames() { // loadcrl can only work with DER encoded files // (verified with dirmngr 1.0.3) const QString filter = QStringLiteral("%1 (*.crl *.arl *-crl.der *-arl.der)").arg(i18n("Certificate Revocation Lists, DER encoded")); return QFileDialog::getOpenFileNames(parentWidgetOrView(), i18n("Select CRL File to Import"), QString(), filter); } #endif // QT_NO_FILEDIALOG private: void slotProcessFinished(int, QProcess::ExitStatus); void slotProcessReadyReadStandardError(); private: QStringList files; QProcess process; QByteArray errorBuffer; bool canceled; bool firstRun; }; ImportCrlCommand::Private *ImportCrlCommand::d_func() { return static_cast(d.get()); } const ImportCrlCommand::Private *ImportCrlCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() ImportCrlCommand::Private::Private(ImportCrlCommand *qq, KeyListController *c) : Command::Private(qq, c), files(), process(), errorBuffer(), canceled(false), firstRun(true) { process.setProgram (gpgSmPath()); process.setArguments(QStringList() << QStringLiteral("--call-dirmngr") << QStringLiteral("loadcrl")); } ImportCrlCommand::Private::~Private() {} ImportCrlCommand::ImportCrlCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } ImportCrlCommand::ImportCrlCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } ImportCrlCommand::ImportCrlCommand(const QStringList &files, KeyListController *c) : Command(new Private(this, c)) { d->init(); d->files = files; } ImportCrlCommand::ImportCrlCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->files = files; } void ImportCrlCommand::Private::init() { connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), q, SLOT(slotProcessFinished(int,QProcess::ExitStatus))); connect(&process, SIGNAL(readyReadStandardError()), q, SLOT(slotProcessReadyReadStandardError())); } ImportCrlCommand::~ImportCrlCommand() {} void ImportCrlCommand::setFiles(const QStringList &files) { d->files = files; } void ImportCrlCommand::doStart() { #ifndef QT_NO_FILEDIALOG if (d->files.empty()) { d->files = d->getFileNames(); } #endif // QT_NO_FILEDIALOG if (d->files.empty()) { Q_EMIT canceled(); d->finished(); return; } auto args = d->process.arguments(); if (!d->firstRun) { /* remove the last file */ args.pop_back(); } args << d->files.takeFirst(); d->process.setArguments(args); d->process.start(); d->firstRun = false; if (!d->process.waitForStarted()) { d->error(i18n("Unable to start process dirmngr. " "Please check your installation."), i18n("Clear CRL Cache Error")); d->finished(); } } void ImportCrlCommand::doCancel() { d->canceled = true; if (d->process.state() != QProcess::NotRunning) { d->process.terminate(); QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, &d->process, &QProcess::kill); } } void ImportCrlCommand::Private::slotProcessFinished(int code, QProcess::ExitStatus status) { if (!canceled) { if (status == QProcess::CrashExit) error(i18n("The GpgSM process that tried to import the CRL file " "ended prematurely because of an unexpected error. " "Please check the output of gpgsm --call-dirmngr loadcrl for details."), i18n("Import CRL Error")); else if (code) error(i18n("An error occurred while trying to import the CRL file. " "The output from gpgsm was:\n%1", errorString()), i18n("Import CRL Error")); else if (files.empty()) information(i18n("CRL file imported successfully."), i18n("Import CRL Finished")); } if (!files.empty()) { q->doStart(); return; } finished(); } void ImportCrlCommand::Private::slotProcessReadyReadStandardError() { errorBuffer += process.readAllStandardError(); } #undef d #undef q #include "moc_importcrlcommand.cpp" diff --git a/src/commands/keytocardcommand.cpp b/src/commands/keytocardcommand.cpp index d1a20aea7..2a78f3977 100644 --- a/src/commands/keytocardcommand.cpp +++ b/src/commands/keytocardcommand.cpp @@ -1,524 +1,524 @@ /* commands/keytocardcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "keytocardcommand.h" #include "cardcommand_p.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/certificateselectiondialog.h" #include "smartcard/openpgpcard.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "smartcard/utils.h" #include #include #include #include #include #include #include #include #include #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36 # define GPG_ERROR_HAS_NO_AUTH #endif #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class KeyToCardCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::KeyToCardCommand; KeyToCardCommand *q_func() const { return static_cast(q); } public: explicit Private(KeyToCardCommand *qq, const GpgME::Subkey &subkey); explicit Private(KeyToCardCommand *qq, const std::string &slot, const std::string &serialNumber, const std::string &appName); - ~Private(); + ~Private() override; private: void start(); void startKeyToOpenPGPCard(); Subkey getSubkeyToTransferToPIVCard(const std::string &cardSlot, const std::shared_ptr &card); void startKeyToPIVCard(); void authenticate(); void authenticationFinished(); void authenticationCanceled(); private: std::string appName; GpgME::Subkey subkey; std::string cardSlot; bool overwriteExistingAlreadyApproved = false; bool hasBeenCanceled = false; }; KeyToCardCommand::Private *KeyToCardCommand::d_func() { return static_cast(d.get()); } const KeyToCardCommand::Private *KeyToCardCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const GpgME::Subkey &subkey_) : CardCommand::Private(qq, "", nullptr) , subkey(subkey_) { } KeyToCardCommand::Private::Private(KeyToCardCommand *qq, const std::string &slot, const std::string &serialNumber, const std::string &appName_) : CardCommand::Private(qq, serialNumber, nullptr) , appName(appName_) , cardSlot(slot) { } KeyToCardCommand::Private::~Private() { } namespace { static std::shared_ptr getCardToTransferSubkeyTo(const Subkey &subkey, QWidget *parent) { const std::vector > suitableCards = KeyToCardCommand::getSuitableCards(subkey); if (suitableCards.empty()) { return std::shared_ptr(); } else if (suitableCards.size() == 1) { return suitableCards[0]; } QStringList options; for (const auto &card: suitableCards) { options.push_back(i18nc("smartcard application - serial number of smartcard", "%1 - %2", displayAppName(card->appName()), card->displaySerialNumber())); } bool ok; const QString choice = QInputDialog::getItem(parent, i18n("Select Card"), i18n("Please select the card the key should be written to:"), options, /* current= */ 0, /* editable= */ false, &ok); if (!ok) { return std::shared_ptr(); } const int index = options.indexOf(choice); return suitableCards[index]; } } void KeyToCardCommand::Private::start() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::start()"; if (!subkey.isNull() && serialNumber().empty()) { const auto card = getCardToTransferSubkeyTo(subkey, parentWidgetOrView()); if (!card) { finished(); return; } setSerialNumber(card->serialNumber()); appName = card->appName(); } const auto card = SmartCard::ReaderStatus::instance()->getCard(serialNumber(), appName); if (!card) { error(i18n("Failed to find the card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } if (card->appName() == SmartCard::OpenPGPCard::AppName) { startKeyToOpenPGPCard(); } else if (card->appName() == SmartCard::PIVCard::AppName) { startKeyToPIVCard(); } else { error(i18n("Sorry! Transferring keys to this card is not supported.")); finished(); return; } } namespace { static int getOpenPGPCardSlotForKey(const GpgME::Subkey &subKey, QWidget *parent) { // Check if we need to ask the user for the slot if ((subKey.canSign() || subKey.canCertify()) && !subKey.canEncrypt() && !subKey.canAuthenticate()) { // Signing only return 1; } if (subKey.canEncrypt() && !(subKey.canSign() || subKey.canCertify()) && !subKey.canAuthenticate()) { // Encrypt only return 2; } if (subKey.canAuthenticate() && !(subKey.canSign() || subKey.canCertify()) && !subKey.canEncrypt()) { // Auth only return 3; } // Multiple uses, ask user. QStringList options; if (subKey.canSign() || subKey.canCertify()) { options << i18nc("Placeholder is the number of a slot on a smart card", "Signature (%1)", 1); } if (subKey.canEncrypt()) { options << i18nc("Placeholder is the number of a slot on a smart card", "Encryption (%1)", 2); } if (subKey.canAuthenticate()) { options << i18nc("Placeholder is the number of a slot on a smart card", "Authentication (%1)", 3); } bool ok; const QString choice = QInputDialog::getItem(parent, i18n("Select Card Slot"), i18n("Please select the card slot the key should be written to:"), options, /* current= */ 0, /* editable= */ false, &ok); const int slot = options.indexOf(choice) + 1; return ok ? slot : -1; } } void KeyToCardCommand::Private::startKeyToOpenPGPCard() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::startKeyToOpenPGPCard()"; const auto pgpCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pgpCard) { error(i18n("Failed to find the OpenPGP card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } if (subkey.isNull()) { finished(); return; } if (subkey.parent().protocol() != GpgME::OpenPGP) { error(i18n("Sorry! This key cannot be transferred to an OpenPGP card.")); finished(); return; } const auto slot = getOpenPGPCardSlotForKey(subkey, parentWidgetOrView()); if (slot < 1) { finished(); return; } // Check if we need to do the overwrite warning. std::string existingKey; QString encKeyWarning; if (slot == 1) { existingKey = pgpCard->keyFingerprint(OpenPGPCard::pgpSigKeyRef()); } else if (slot == 2) { existingKey = pgpCard->keyFingerprint(OpenPGPCard::pgpEncKeyRef()); encKeyWarning = i18n("It will no longer be possible to decrypt past communication " "encrypted for the existing key."); } else if (slot == 3) { existingKey = pgpCard->keyFingerprint(OpenPGPCard::pgpAuthKeyRef()); } if (!existingKey.empty()) { const QString message = i18nc("@info", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the fingerprint:") + QStringLiteral("
%1
").arg(QString::fromStdString(existingKey)) + encKeyWarning; const auto choice = KMessageBox::warningContinueCancel(parentWidgetOrView(), message, i18nc("@title:window", "Overwrite existing key"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (choice != KMessageBox::Continue) { finished(); return; } } // Now do the deed const auto time = QDateTime::fromSecsSinceEpoch(subkey.creationTime(), Qt::UTC); const auto timestamp = time.toString(QStringLiteral("yyyyMMdd'T'HHmmss")); const QString cmd = QStringLiteral("KEYTOCARD --force %1 %2 OPENPGP.%3 %4") .arg(QString::fromLatin1(subkey.keyGrip()), QString::fromStdString(serialNumber())) .arg(slot) .arg(timestamp); ReaderStatus::mutableInstance()->startSimpleTransaction(pgpCard, cmd.toUtf8(), q_func(), "keyToOpenPGPCardDone"); } namespace { static std::vector getSigningCertificates() { std::vector signingCertificates = KeyCache::instance()->secretKeys(); const auto it = std::remove_if(signingCertificates.begin(), signingCertificates.end(), [](const Key &key) { return ! (key.protocol() == GpgME::CMS && !key.subkey(0).isNull() && key.subkey(0).canSign() && !key.subkey(0).canEncrypt() && key.subkey(0).isSecret() && !key.subkey(0).isCardKey()); }); signingCertificates.erase(it, signingCertificates.end()); return signingCertificates; } static std::vector getEncryptionCertificates() { std::vector encryptionCertificates = KeyCache::instance()->secretKeys(); const auto it = std::remove_if(encryptionCertificates.begin(), encryptionCertificates.end(), [](const Key &key) { return ! (key.protocol() == GpgME::CMS && !key.subkey(0).isNull() && key.subkey(0).canEncrypt() && key.subkey(0).isSecret() && !key.subkey(0).isCardKey()); }); encryptionCertificates.erase(it, encryptionCertificates.end()); return encryptionCertificates; } } Subkey KeyToCardCommand::Private::getSubkeyToTransferToPIVCard(const std::string &cardSlot, const std::shared_ptr &/*card*/) { if (cardSlot != PIVCard::cardAuthenticationKeyRef() && cardSlot != PIVCard::keyManagementKeyRef()) { return Subkey(); } const std::vector certificates = cardSlot == PIVCard::cardAuthenticationKeyRef() ? getSigningCertificates() : getEncryptionCertificates(); if (certificates.empty()) { error(i18n("Sorry! No suitable certificate to write to this card slot was found.")); return Subkey(); } auto dialog = new KeySelectionDialog(parentWidgetOrView()); dialog->setWindowTitle(i18nc("@title:window", "Select Certificate")); dialog->setText(i18n("Please select the certificate whose key pair you want to write to the card:")); dialog->setKeys(certificates); if (dialog->exec() == QDialog::Rejected) { return Subkey(); } return dialog->selectedKey().subkey(0); } void KeyToCardCommand::Private::startKeyToPIVCard() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::Private::startKeyToPIVCard()"; const auto pivCard = SmartCard::ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } if (cardSlot != PIVCard::cardAuthenticationKeyRef() && cardSlot != PIVCard::keyManagementKeyRef()) { // key to card is only supported for the Card Authentication key and the Key Management key finished(); return; } if (subkey.isNull()) { subkey = getSubkeyToTransferToPIVCard(cardSlot, pivCard); } if (subkey.isNull()) { finished(); return; } if (subkey.parent().protocol() != GpgME::CMS) { error(i18n("Sorry! This key cannot be transferred to a PIV card.")); finished(); return; } if (!subkey.canEncrypt() && !subkey.canSign()) { error(i18n("Sorry! Only encryption keys and signing keys can be transferred to a PIV card.")); finished(); return; } // Check if we need to do the overwrite warning. if (!overwriteExistingAlreadyApproved) { const std::string existingKey = pivCard->keyInfo(cardSlot).grip; if (!existingKey.empty() && (existingKey != subkey.keyGrip())) { const QString decryptionWarning = (cardSlot == PIVCard::keyManagementKeyRef()) ? i18n("It will no longer be possible to decrypt past communication encrypted for the existing key.") : QString(); const QString message = i18nc("@info", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the key grip:") + QStringLiteral("
%1
").arg(QString::fromStdString(existingKey)) + decryptionWarning; const auto choice = KMessageBox::warningContinueCancel(parentWidgetOrView(), message, i18nc("@title:window", "Overwrite existing key"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (choice != KMessageBox::Continue) { finished(); return; } overwriteExistingAlreadyApproved = true; } } const QString cmd = QStringLiteral("KEYTOCARD --force %1 %2 %3") .arg(QString::fromLatin1(subkey.keyGrip()), QString::fromStdString(serialNumber())) .arg(QString::fromStdString(cardSlot)); ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, cmd.toUtf8(), q_func(), "keyToPIVCardDone"); } void KeyToCardCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticate()"; auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void KeyToCardCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticationFinished()"; if (!hasBeenCanceled) { startKeyToPIVCard(); } } void KeyToCardCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } KeyToCardCommand::KeyToCardCommand(const GpgME::Subkey &subkey) : CardCommand(new Private(this, subkey)) { } KeyToCardCommand::KeyToCardCommand(const std::string& cardSlot, const std::string &serialNumber, const std::string &appName) : CardCommand(new Private(this, cardSlot, serialNumber, appName)) { } KeyToCardCommand::~KeyToCardCommand() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::~KeyToCardCommand()"; } // static std::vector > KeyToCardCommand::getSuitableCards(const GpgME::Subkey &subkey) { std::vector > suitableCards; if (subkey.isNull() || subkey.parent().protocol() != GpgME::OpenPGP) { return suitableCards; } for (const auto &card: ReaderStatus::instance()->getCards()) { if (card->appName() == OpenPGPCard::AppName) { suitableCards.push_back(card); } } return suitableCards; } void KeyToCardCommand::keyToOpenPGPCardDone(const GpgME::Error &err) { if (err) { d->error(i18nc("@info", "Moving the key to the card failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { /* TODO DELETE_KEY is too strong, because it also deletes the stub * of the secret key. I could not find out how GnuPG does this. Question * to GnuPG Developers is pending an answer if (KMessageBox::questionYesNo(d->parentWidgetOrView(), i18n("Do you want to delete the key on this computer?"), i18nc("@title:window", "Key transferred to card")) == KMessageBox::Yes) { const QString cmd = QStringLiteral("DELETE_KEY --force %1").arg(d->subkey.keyGrip()); // Using readerstatus is a bit overkill but it's an easy way to talk to the agent. ReaderStatus::mutableInstance()->startSimpleTransaction(card, cmd.toUtf8(), this, "deleteDone"); } */ d->information(i18nc("@info", "Successfully copied the key to the card."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } d->finished(); } void KeyToCardCommand::keyToPIVCardDone(const GpgME::Error &err) { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::keyToPIVCardDone():" << err.asString() << "(" << err.code() << ")"; if (err) { #ifdef GPG_ERROR_HAS_NO_AUTH // gpgme 1.13 reports "BAD PIN" instead of "NO AUTH" if (err.code() == GPG_ERR_NO_AUTH || err.code() == GPG_ERR_BAD_PIN) { d->authenticate(); return; } #endif d->error(i18nc("@info", "Copying the key pair to the card failed: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { d->information(i18nc("@info", "Successfully copied the key pair to the card."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } d->finished(); } void KeyToCardCommand::deleteDone(const GpgME::Error &err) { if (err) { d->error(i18nc("@info", "Failed to delete the key: %1", QString::fromUtf8(err.asString())), i18nc("@title", "Error")); } d->finished(); } void KeyToCardCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "KeyToCardCommand::doStart()"; d->start(); } void KeyToCardCommand::doCancel() { } #undef q_func #undef d_func diff --git a/src/commands/lookupcertificatescommand.cpp b/src/commands/lookupcertificatescommand.cpp index 31ab1dead..9b2bc9fd1 100644 --- a/src/commands/lookupcertificatescommand.cpp +++ b/src/commands/lookupcertificatescommand.cpp @@ -1,404 +1,404 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/lookupcertificatescommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008, 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "lookupcertificatescommand.h" #include "importcertificatescommand_p.h" #include "detailscommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace GpgME; using namespace QGpgME; class LookupCertificatesCommand::Private : public ImportCertificatesCommand::Private { friend class ::Kleo::Commands::LookupCertificatesCommand; LookupCertificatesCommand *q_func() const { return static_cast(q); } public: explicit Private(LookupCertificatesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QString query; void init(); private: void slotSearchTextChanged(const QString &str); void slotNextKey(const Key &key) { keyListing.keys.push_back(key); } void slotKeyListResult(const KeyListResult &result); void slotImportRequested(const std::vector &keys); void slotDetailsRequested(const Key &key); void slotSaveAsRequested(const std::vector &keys); void slotDialogRejected() { canceled(); } private: using ImportCertificatesCommand::Private::showError; void showError(QWidget *parent, const KeyListResult &result); void showResult(QWidget *parent, const KeyListResult &result); void createDialog(); KeyListJob *createKeyListJob(GpgME::Protocol proto) const { const auto cbp = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); return cbp ? cbp->keyListJob(true) : nullptr; } ImportFromKeyserverJob *createImportJob(GpgME::Protocol proto) const { const auto cbp = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); return cbp ? cbp->importFromKeyserverJob() : nullptr; } void startKeyListJob(GpgME::Protocol proto, const QString &str); bool checkConfig() const; QWidget *dialogOrParentWidgetOrView() const { if (dialog) { return dialog; } else { return parentWidgetOrView(); } } private: QPointer dialog; struct KeyListingVariables { QPointer cms, openpgp; KeyListResult result; std::vector keys; void reset() { *this = KeyListingVariables(); } } keyListing; }; LookupCertificatesCommand::Private *LookupCertificatesCommand::d_func() { return static_cast(d.get()); } const LookupCertificatesCommand::Private *LookupCertificatesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() LookupCertificatesCommand::Private::Private(LookupCertificatesCommand *qq, KeyListController *c) : ImportCertificatesCommand::Private(qq, c), dialog() { } LookupCertificatesCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); delete dialog; } LookupCertificatesCommand::LookupCertificatesCommand(KeyListController *c) : ImportCertificatesCommand(new Private(this, c)) { d->init(); } LookupCertificatesCommand::LookupCertificatesCommand(const QString &query, KeyListController *c) : ImportCertificatesCommand(new Private(this, c)) { d->init(); d->query = query; } LookupCertificatesCommand::LookupCertificatesCommand(QAbstractItemView *v, KeyListController *c) : ImportCertificatesCommand(v, new Private(this, c)) { d->init(); } void LookupCertificatesCommand::Private::init() { } LookupCertificatesCommand::~LookupCertificatesCommand() { qCDebug(KLEOPATRA_LOG); } void LookupCertificatesCommand::doStart() { if (!d->checkConfig()) { d->finished(); return; } d->createDialog(); Q_ASSERT(d->dialog); // if we have a prespecified query, load it into find field // and start the search if (!d->query.isEmpty()) { d->dialog->setSearchText(d->query); d->slotSearchTextChanged(d->query); } else { d->dialog->setPassive(false); } d->dialog->show(); } void LookupCertificatesCommand::Private::createDialog() { if (dialog) { return; } dialog = new LookupCertificatesDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(searchTextChanged(QString)), q, SLOT(slotSearchTextChanged(QString))); connect(dialog, SIGNAL(saveAsRequested(std::vector)), q, SLOT(slotSaveAsRequested(std::vector))); connect(dialog, SIGNAL(importRequested(std::vector)), q, SLOT(slotImportRequested(std::vector))); connect(dialog, SIGNAL(detailsRequested(GpgME::Key)), q, SLOT(slotDetailsRequested(GpgME::Key))); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void LookupCertificatesCommand::Private::slotSearchTextChanged(const QString &str) { // pressing return might trigger both search and dialog destruction (search focused and default key set) // On Windows, the dialog is then destroyed before this slot is called if (dialog) { //thus test dialog->setPassive(true); dialog->setCertificates(std::vector()); } query = str; startKeyListJob(CMS, str); const QRegExp rx(QLatin1String("(?:0x|0X)?[0-9a-fA-F]{6,}")); if (rx.exactMatch(query) && !str.startsWith(QLatin1String("0x"), Qt::CaseInsensitive)) { qCDebug(KLEOPATRA_LOG) << "Adding 0x prefix to query"; startKeyListJob(OpenPGP, QStringLiteral("0x") + str); } else { startKeyListJob(OpenPGP, str); } } void LookupCertificatesCommand::Private::startKeyListJob(GpgME::Protocol proto, const QString &str) { KeyListJob *const klj = createKeyListJob(proto); if (!klj) { return; } connect(klj, SIGNAL(result(GpgME::KeyListResult)), q, SLOT(slotKeyListResult(GpgME::KeyListResult))); connect(klj, SIGNAL(nextKey(GpgME::Key)), q, SLOT(slotNextKey(GpgME::Key))); if (const Error err = klj->start(QStringList(str))) { keyListing.result.mergeWith(KeyListResult(err)); } else if (proto == CMS) { keyListing.cms = klj; } else { keyListing.openpgp = klj; } } void LookupCertificatesCommand::Private::slotKeyListResult(const KeyListResult &r) { if (q->sender() == keyListing.cms) { keyListing.cms = nullptr; } else if (q->sender() == keyListing.openpgp) { keyListing.openpgp = nullptr; } else { qCDebug(KLEOPATRA_LOG) << "unknown sender()" << q->sender(); } keyListing.result.mergeWith(r); if (keyListing.cms || keyListing.openpgp) { // still waiting for jobs to complete return; } if (keyListing.result.error() && !keyListing.result.error().isCanceled()) { showError(dialog, keyListing.result); } if (keyListing.result.isTruncated()) { showResult(dialog, keyListing.result); } if (dialog) { dialog->setPassive(false); dialog->setCertificates(keyListing.keys); } else { finished(); } keyListing.reset(); } void LookupCertificatesCommand::Private::slotImportRequested(const std::vector &keys) { dialog = nullptr; Q_ASSERT(!keys.empty()); Q_ASSERT(std::none_of(keys.cbegin(), keys.cend(), [](const Key &key) { return key.isNull(); })); std::vector pgp, cms; pgp.reserve(keys.size()); cms.reserve(keys.size()); kdtools::separate_if(keys.begin(), keys.end(), std::back_inserter(pgp), std::back_inserter(cms), [](const Key &key) { return key.protocol() == GpgME::OpenPGP; }); setWaitForMoreJobs(true); if (!pgp.empty()) startImport(OpenPGP, pgp, i18nc(R"(@title %1:"OpenPGP" or "CMS")", "%1 Certificate Server", Formatting::displayName(OpenPGP))); if (!cms.empty()) startImport(CMS, cms, i18nc(R"(@title %1:"OpenPGP" or "CMS")", "%1 Certificate Server", Formatting::displayName(CMS))); setWaitForMoreJobs(false); } void LookupCertificatesCommand::Private::slotSaveAsRequested(const std::vector &keys) { Q_UNUSED(keys) qCDebug(KLEOPATRA_LOG) << "not implemented"; } void LookupCertificatesCommand::Private::slotDetailsRequested(const Key &key) { Command *const cmd = new DetailsCommand(key, view(), controller()); cmd->setParentWidget(dialogOrParentWidgetOrView()); cmd->start(); } void LookupCertificatesCommand::doCancel() { ImportCertificatesCommand::doCancel(); if (QDialog *const dlg = d->dialog) { d->dialog = nullptr; dlg->close(); } } void LookupCertificatesCommand::Private::showError(QWidget *parent, const KeyListResult &result) { if (!result.error()) { return; } KMessageBox::information(parent, i18nc("@info", "Failed to search on certificate server. The error returned was:\n%1", QString::fromLocal8Bit(result.error().asString()))); } void LookupCertificatesCommand::Private::showResult(QWidget *parent, const KeyListResult &result) { if (result.isTruncated()) KMessageBox::information(parent, xi18nc("@info", "The query result has been truncated." "Either the local or a remote limit on " "the maximum number of returned hits has " "been exceeded." "You can try to increase the local limit " "in the configuration dialog, but if one " "of the configured servers is the limiting " "factor, you have to refine your search."), i18nc("@title", "Result Truncated"), QStringLiteral("lookup-certificates-truncated-result")); } static bool haveX509DirectoryServerConfigured() { const QGpgME::CryptoConfig *const config = QGpgME::cryptoConfig(); if (!config) { return false; } const QGpgME::CryptoConfigEntry *entry = getCryptoConfigEntry(config, "dirmngr", "LDAP Server"); bool entriesExist = entry && !entry->urlValueList().empty(); entry = getCryptoConfigEntry(config, "gpgsm", "keyserver"); entriesExist |= entry && !entry->urlValueList().empty(); return entriesExist; } bool LookupCertificatesCommand::Private::checkConfig() const { const bool ok = haveKeyserverConfigured() || haveX509DirectoryServerConfigured(); if (!ok) information(xi18nc("@info", "You do not have any directory servers configured." "You need to configure at least one directory server to " "search on one." "You can configure directory servers here: " "Settings->Configure Kleopatra."), i18nc("@title", "No Directory Servers Configured")); return ok; } #undef d #undef q #include "moc_lookupcertificatescommand.cpp" diff --git a/src/commands/newcertificatecommand.cpp b/src/commands/newcertificatecommand.cpp index ef6b8ba42..6c6aac91a 100644 --- a/src/commands/newcertificatecommand.cpp +++ b/src/commands/newcertificatecommand.cpp @@ -1,160 +1,160 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/newcertificatecommand.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 "newcertificatecommand.h" #include "command_p.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; class NewCertificateCommand::Private : public Command::Private { friend class ::Kleo::Commands::NewCertificateCommand; NewCertificateCommand *q_func() const { return static_cast(q); } public: explicit Private(NewCertificateCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotDialogRejected(); void slotDialogAccepted(); private: void ensureDialogCreated(); private: Protocol protocol; QPointer dialog; }; NewCertificateCommand::Private *NewCertificateCommand::d_func() { return static_cast(d.get()); } const NewCertificateCommand::Private *NewCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() NewCertificateCommand::Private::Private(NewCertificateCommand *qq, KeyListController *c) : Command::Private(qq, c), protocol(UnknownProtocol), dialog() { } NewCertificateCommand::Private::~Private() {} NewCertificateCommand::NewCertificateCommand() : Command(new Private(this, nullptr)) { d->init(); } NewCertificateCommand::NewCertificateCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } NewCertificateCommand::NewCertificateCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void NewCertificateCommand::Private::init() { } NewCertificateCommand::~NewCertificateCommand() {} void NewCertificateCommand::setProtocol(Protocol proto) { d->protocol = proto; if (d->dialog) { d->dialog->setProtocol(proto); } } Protocol NewCertificateCommand::protocol() const { if (d->dialog) { return d->dialog->protocol(); } else { return d->protocol; } } void NewCertificateCommand::doStart() { d->ensureDialogCreated(); Q_ASSERT(d->dialog); if (d->protocol != UnknownProtocol) { d->dialog->setProtocol(d->protocol); } d->dialog->show(); } void NewCertificateCommand::Private::slotDialogRejected() { Q_EMIT q->canceled(); finished(); } void NewCertificateCommand::Private::slotDialogAccepted() { finished(); } void NewCertificateCommand::doCancel() { if (d->dialog) { d->dialog->close(); } } void NewCertificateCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new NewCertificateWizard; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); } #undef d #undef q #include "moc_newcertificatecommand.cpp" diff --git a/src/commands/pivgeneratecardkeycommand.cpp b/src/commands/pivgeneratecardkeycommand.cpp index 75c0f4107..fc78b9d4c 100644 --- a/src/commands/pivgeneratecardkeycommand.cpp +++ b/src/commands/pivgeneratecardkeycommand.cpp @@ -1,254 +1,254 @@ /* commands/pivgeneratecardkeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "pivgeneratecardkeycommand.h" #include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/gencardkeydialog.h" #include #include #include #if GPG_ERROR_VERSION_NUMBER >= 0x12400 // 1.36 # define GPG_ERROR_HAS_NO_AUTH #endif #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::SmartCard; using namespace GpgME; class PIVGenerateCardKeyCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::PIVGenerateCardKeyCommand; PIVGenerateCardKeyCommand *q_func() const { return static_cast(q); } public: explicit Private(PIVGenerateCardKeyCommand *qq, const std::string &serialNumber, QWidget *p); - ~Private(); + ~Private() override; void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void authenticate(); void authenticationFinished(); void authenticationCanceled(); void generateKey(); void ensureDialogCreated(); private: std::string keyRef; bool overwriteExistingKey = false; std::string algorithm; QPointer dialog; bool hasBeenCanceled = false; }; PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func() { return static_cast(d.get()); } const PIVGenerateCardKeyCommand::Private *PIVGenerateCardKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() PIVGenerateCardKeyCommand::Private::Private(PIVGenerateCardKeyCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , dialog() { } PIVGenerateCardKeyCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::Private::~Private()"; } PIVGenerateCardKeyCommand::PIVGenerateCardKeyCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void PIVGenerateCardKeyCommand::Private::init() { } PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::~PIVGenerateCardKeyCommand()"; } void PIVGenerateCardKeyCommand::setKeyRef(const std::string &keyRef) { d->keyRef = keyRef; } void PIVGenerateCardKeyCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::doStart()"; // check if key exists auto pivCard = ReaderStatus::instance()->getCard(d->serialNumber()); if (!pivCard) { d->error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(d->serialNumber()))); d->finished(); return; } auto existingKey = pivCard->keyInfo(d->keyRef).grip; if (!existingKey.empty()) { const QString warningText = i18nc("@info", "

This card already contains a key in this slot. Continuing will overwrite that key.

" "

If there is no backup the existing key will be irrecoverably lost.

") + i18n("The existing key has the ID:") + QStringLiteral("
%1
").arg(QString::fromStdString(existingKey)) + (d->keyRef == PIVCard::keyManagementKeyRef() ? i18n("It will no longer be possible to decrypt past communication encrypted for the existing key.") : QString()); const auto choice = KMessageBox::warningContinueCancel(d->parentWidgetOrView(), warningText, i18nc("@title:window", "Overwrite existing key"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous); if (choice != KMessageBox::Continue) { d->finished(); return; } d->overwriteExistingKey = true; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); d->dialog->show(); } void PIVGenerateCardKeyCommand::doCancel() { } void PIVGenerateCardKeyCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticate()"; auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void PIVGenerateCardKeyCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationFinished()"; if (!hasBeenCanceled) { generateKey(); } } void PIVGenerateCardKeyCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } void PIVGenerateCardKeyCommand::Private::generateKey() { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::generateKey()"; auto pivCard = ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } QByteArrayList command; command << "SCD GENKEY"; if (overwriteExistingKey) { command << "--force"; } if (!algorithm.empty()) { command << "--algo=" + QByteArray::fromStdString(algorithm); } command << "--" << QByteArray::fromStdString(keyRef); ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command.join(' '), q, "slotResult"); } void PIVGenerateCardKeyCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "PIVGenerateCardKeyCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err) { #ifdef GPG_ERROR_HAS_NO_AUTH if (err.code() == GPG_ERR_NO_AUTH) { authenticate(); return; } #endif error(i18nc("@info", "Generating key failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { information(i18nc("@info", "Key successfully generated."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } finished(); } void PIVGenerateCardKeyCommand::Private::slotDialogAccepted() { algorithm = dialog->getKeyParams().algorithm; // assume that we are already authenticated to the card generateKey(); } void PIVGenerateCardKeyCommand::Private::slotDialogRejected() { finished(); } void PIVGenerateCardKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new GenCardKeyDialog(GenCardKeyDialog::KeyAlgorithm, parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setSupportedAlgorithms(PIVCard::supportedAlgorithms(keyRef), "rsa2048"); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } #undef d #undef q #include "moc_pivgeneratecardkeycommand.cpp" diff --git a/src/commands/reloadkeyscommand.cpp b/src/commands/reloadkeyscommand.cpp index a2e1e0aef..bbaa36ccc 100644 --- a/src/commands/reloadkeyscommand.cpp +++ b/src/commands/reloadkeyscommand.cpp @@ -1,97 +1,97 @@ /* -*- mode: c++; c-basic-offset:4 -*- reloadkeyscommand.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 "reloadkeyscommand.h" #include "smartcard/readerstatus.h" #include "command_p.h" #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace GpgME; class ReloadKeysCommand::Private : public Command::Private { friend class ::Kleo::ReloadKeysCommand; public: Private(ReloadKeysCommand *qq, KeyListController *controller); - ~Private(); + ~Private() override; void keyListingDone(const KeyListResult &result); }; ReloadKeysCommand::Private *ReloadKeysCommand::d_func() { return static_cast(d.get()); } const ReloadKeysCommand::Private *ReloadKeysCommand::d_func() const { return static_cast(d.get()); } ReloadKeysCommand::ReloadKeysCommand(KeyListController *p) : Command(new Private(this, p)) { } ReloadKeysCommand::ReloadKeysCommand(QAbstractItemView *v, KeyListController *p) : Command(v, new Private(this, p)) { } ReloadKeysCommand::~ReloadKeysCommand() {} ReloadKeysCommand::Private::Private(ReloadKeysCommand *qq, KeyListController *controller) : Command::Private(qq, controller) { } ReloadKeysCommand::Private::~Private() {} void ReloadKeysCommand::Private::keyListingDone(const KeyListResult &result) { if (result.error()) { // ### Show error message here? qCritical() << "Error occurred during key listing: " << result.error().asString(); } finished(); } #define d d_func() void ReloadKeysCommand::doStart() { const auto view = d->parentWidgetOrView(); if (view && !view->isVisible()) { // Small hack to make redisplay also work nicely when the keylist // is not currently the active widget. SmartCard::ReaderStatus::mutableInstance()->updateStatus(); d->finished(); return; } connect(KeyCache::mutableInstance().get(), SIGNAL(keyListingDone(GpgME::KeyListResult)), this, SLOT(keyListingDone(GpgME::KeyListResult))); KeyCache::mutableInstance()->startKeyListing(); } void ReloadKeysCommand::doCancel() { KeyCache::mutableInstance()->cancelKeyListing(); } #undef d #include "moc_reloadkeyscommand.cpp" diff --git a/src/commands/revokecertificationcommand.cpp b/src/commands/revokecertificationcommand.cpp index c56a7a1f8..54dc373ef 100644 --- a/src/commands/revokecertificationcommand.cpp +++ b/src/commands/revokecertificationcommand.cpp @@ -1,254 +1,254 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/revokecertificationcommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "revokecertificationcommand.h" #include "command_p.h" #include "exportopenpgpcertstoservercommand.h" #include "dialogs/revokecertificationdialog.h" #include #include #include #include #include #include #include "kleopatra_debug.h" #include #if GPGMEPP_VERSION >= 0x10E01 // 1.14.1 # define GPGME_HAS_REVSIG #endif using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; using namespace QGpgME; class RevokeCertificationCommand::Private : public Command::Private { friend class ::Kleo::Commands::RevokeCertificationCommand; RevokeCertificationCommand *q_func() const { return static_cast(q); } public: explicit Private(RevokeCertificationCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void ensureDialogCreated(); void createJob(); private: Key certificationKey; Key certificationTarget; std::vector uids; QPointer dialog; QPointer job; }; RevokeCertificationCommand::Private *RevokeCertificationCommand::d_func() { return static_cast(d.get()); } const RevokeCertificationCommand::Private *RevokeCertificationCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() RevokeCertificationCommand::Private::Private(RevokeCertificationCommand *qq, KeyListController *c) : Command::Private(qq, c) { } RevokeCertificationCommand::Private::~Private() { } void RevokeCertificationCommand::Private::init() { const std::vector keys_ = keys(); if (keys_.size() != 1) { qCWarning(KLEOPATRA_LOG) << "RevokeCertificationCommand::Private::init: Expected exactly one key, but got" << keys_.size(); return; } if (keys_.front().protocol() != GpgME::OpenPGP) { qCWarning(KLEOPATRA_LOG) << "RevokeCertificationCommand::Private::init: Expected OpenPGP key, but got" << keys_.front().protocolAsString(); return; } certificationTarget = keys_.front(); } void RevokeCertificationCommand::Private::slotDialogAccepted() { createJob(); #ifdef GPGME_HAS_REVSIG job->startRevokeSignature(certificationTarget, dialog->selectedCertificationKey(), dialog->selectedUserIDs()); #endif } void RevokeCertificationCommand::Private::slotDialogRejected() { canceled(); } void RevokeCertificationCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) { // do nothing } else if (err) { error(i18n("

An error occurred while trying to revoke the certification of

" "%1:

\t%2

", Formatting::formatForComboBox(certificationTarget), QString::fromUtf8(err.asString())), i18n("Revocation Error")); } else { information(i18n("Revocation successful."), i18n("Revocation Succeeded")); if (dialog && dialog->sendToServer()) { auto const cmd = new ExportOpenPGPCertsToServerCommand(certificationTarget); cmd->start(); } } finished(); } void RevokeCertificationCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new RevokeCertificationDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void RevokeCertificationCommand::Private::createJob() { Q_ASSERT(!job); Q_ASSERT(certificationTarget.protocol() == OpenPGP); const auto backend = QGpgME::openpgp(); if (!backend) { return; } QuickJob *const j = backend->quickJob(); if (!j) { return; } connect(j, &Job::progress, q, &Command::progress); connect(j, SIGNAL(result(GpgME::Error)), q, SLOT(slotResult(GpgME::Error))); job = j; } RevokeCertificationCommand::RevokeCertificationCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } RevokeCertificationCommand::RevokeCertificationCommand(const GpgME::UserID &uid) : Command(uid.parent(), new Private(this, nullptr)) { std::vector(1, uid).swap(d->uids); d->init(); } RevokeCertificationCommand::RevokeCertificationCommand(const GpgME::UserID::Signature &signature) : Command(signature.parent().parent(), new Private(this, nullptr)) { std::vector(1, signature.parent()).swap(d->uids); d->certificationKey = KeyCache::instance()->findByKeyIDOrFingerprint(signature.signerKeyID()); d->init(); } RevokeCertificationCommand::~RevokeCertificationCommand() { qCDebug(KLEOPATRA_LOG) << "~RevokeCertificationCommand()"; } // static bool RevokeCertificationCommand::isSupported() { #ifdef GPGME_HAS_REVSIG return engineInfo(GpgEngine).engineVersion() >= "2.2.24"; #else return false; #endif } void RevokeCertificationCommand::doStart() { if (d->certificationTarget.isNull()) { d->finished(); return; } for (const UserID &uid : std::as_const(d->uids)) if (qstricmp(uid.parent().primaryFingerprint(), d->certificationTarget.primaryFingerprint()) != 0) { qCWarning(KLEOPATRA_LOG) << "User-ID <-> Key mismatch!"; d->finished(); return; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); d->dialog->setCertificateToRevoke(d->certificationTarget); if (!d->uids.empty()) { d->dialog->setSelectedUserIDs(d->uids); } if (!d->certificationKey.isNull()) { d->dialog->setSelectedCertificationKey(d->certificationKey); } d->dialog->show(); } void RevokeCertificationCommand::doCancel() { qCDebug(KLEOPATRA_LOG) << "RevokeCertificationCommand::doCancel()"; if (d->job) { d->job->slotCancel(); } } #undef d #undef q #include "moc_revokecertificationcommand.cpp" diff --git a/src/commands/selftestcommand.cpp b/src/commands/selftestcommand.cpp index 6a7ac88be..0c95b0ee4 100644 --- a/src/commands/selftestcommand.cpp +++ b/src/commands/selftestcommand.cpp @@ -1,270 +1,270 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/selftestcommand.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 "selftestcommand.h" #include "command_p.h" #include #include "kleopatra_debug.h" #ifdef Q_OS_WIN # include #endif #include #include #ifdef HAVE_KLEOPATRACLIENT_LIBRARY # include #endif #include #include #include #include #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; static const char *const components[] = { nullptr, // gpgconf "gpg", "gpg-agent", "scdaemon", "gpgsm", "dirmngr", }; static const unsigned int numComponents = sizeof components / sizeof * components; class SelfTestCommand::Private : Command::Private { friend class ::Kleo::Commands::SelfTestCommand; SelfTestCommand *q_func() const { return static_cast(q); } public: explicit Private(SelfTestCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; private: void init(); void ensureDialogCreated() { if (dialog) { return; } dialog = new SelfTestDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, SIGNAL(updateRequested()), q_func(), SLOT(slotUpdateRequested())); connect(dialog, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected())); dialog->setRunAtStartUp(runAtStartUp()); dialog->setAutomaticMode(automatic); } void ensureDialogShown() { ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } } bool runAtStartUp() const { const KConfigGroup config(KSharedConfig::openConfig(), "Self-Test"); return config.readEntry("run-at-startup", true); } void setRunAtStartUp(bool on) { KConfigGroup config(KSharedConfig::openConfig(), "Self-Test"); config.writeEntry("run-at-startup", on); } void runTests() { std::vector< std::shared_ptr > tests; #if defined(Q_OS_WIN) qCDebug(KLEOPATRA_LOG) << "Checking Windows Registry..."; tests.push_back(makeGpgProgramRegistryCheckSelfTest()); #if defined(HAVE_KLEOPATRACLIENT_LIBRARY) qCDebug(KLEOPATRA_LOG) << "Checking Ui Server connectivity..."; tests.push_back(makeUiServerConnectivitySelfTest()); #endif #endif qCDebug(KLEOPATRA_LOG) << "Checking gpg installation..."; tests.push_back(makeGpgEngineCheckSelfTest()); qCDebug(KLEOPATRA_LOG) << "Checking gpgsm installation..."; tests.push_back(makeGpgSmEngineCheckSelfTest()); qCDebug(KLEOPATRA_LOG) << "Checking gpgconf installation..."; tests.push_back(makeGpgConfEngineCheckSelfTest()); for (unsigned int i = 0; i < numComponents; ++i) { qCDebug(KLEOPATRA_LOG) << "Checking configuration of:" << components[i]; tests.push_back(makeGpgConfCheckConfigurationSelfTest(components[i])); } #ifndef Q_OS_WIN tests.push_back(makeGpgAgentConnectivitySelfTest()); #endif tests.push_back(makeLibKleopatraRcSelfTest()); if (!dialog && std::none_of(tests.cbegin(), tests.cend(), [](const std::shared_ptr &test) { return test->failed(); })) { finished(); return; } ensureDialogCreated(); dialog->clear(); dialog->addSelfTests(tests); ensureDialogShown(); } private: void slotDialogAccepted() { setRunAtStartUp(dialog->runAtStartUp()); finished(); } void slotDialogRejected() { if (automatic) { canceled = true; Command::Private::canceled(); } else { slotDialogAccepted(); } } void slotUpdateRequested() { const auto conf = QGpgME::cryptoConfig(); if (conf) { conf->clear(); } runTests(); } private: QPointer dialog; bool canceled; bool automatic; }; SelfTestCommand::Private *SelfTestCommand::d_func() { return static_cast(d.get()); } const SelfTestCommand::Private *SelfTestCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SelfTestCommand::Private::Private(SelfTestCommand *qq, KeyListController *c) : Command::Private(qq, c), dialog(), canceled(false), automatic(false) { } SelfTestCommand::Private::~Private() { } SelfTestCommand::SelfTestCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } SelfTestCommand::SelfTestCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } void SelfTestCommand::Private::init() { } SelfTestCommand::~SelfTestCommand() {} void SelfTestCommand::setAutomaticMode(bool on) { d->automatic = on; if (d->dialog) { d->dialog->setAutomaticMode(on); } } bool SelfTestCommand::isCanceled() const { return d->canceled; } void SelfTestCommand::doStart() { if (d->automatic) { if (!d->runAtStartUp()) { d->finished(); return; } } else { d->ensureDialogCreated(); } d->runTests(); } void SelfTestCommand::doCancel() { d->canceled = true; if (d->dialog) { d->dialog->close(); } d->dialog = nullptr; } #undef d #undef q #include "moc_selftestcommand.cpp" diff --git a/src/commands/setinitialpincommand.cpp b/src/commands/setinitialpincommand.cpp index c687bcc11..15712d98f 100644 --- a/src/commands/setinitialpincommand.cpp +++ b/src/commands/setinitialpincommand.cpp @@ -1,178 +1,178 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/setinitialpincommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "setinitialpincommand.h" #include "cardcommand_p.h" #include "dialogs/setinitialpindialog.h" #include "smartcard/netkeycard.h" #include "smartcard/readerstatus.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class SetInitialPinCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::SetInitialPinCommand; SetInitialPinCommand *q_func() const { return static_cast(q); } public: explicit Private(SetInitialPinCommand *qq, const std::string &serialNumber); - ~Private(); + ~Private() override; private: void init() { } void ensureDialogCreated() const { if (dialog) { return; } auto dlg = new SetInitialPinDialog; applyWindowID(dlg); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setWindowTitle(i18nc("@title:window", "Set Initial Pin")); connect(dlg, SIGNAL(nksPinRequested()), q_func(), SLOT(slotNksPinRequested())); connect(dlg, SIGNAL(sigGPinRequested()), q_func(), SLOT(slotSigGPinRequested())); connect(dlg, SIGNAL(rejected()), q_func(), SLOT(slotDialogRejected())); connect(dlg, SIGNAL(accepted()), q_func(), SLOT(slotDialogAccepted())); dialog = dlg; } void ensureDialogVisible() { ensureDialogCreated(); if (dialog->isVisible()) { dialog->raise(); } else { dialog->show(); } } private: void setInitialPin(const char *pinRef, const char *resultSlot) { const auto nksCard = ReaderStatus::instance()->getCard(serialNumber()); if (!nksCard) { error(i18n("Failed to find the NetKey card with the serial number: %1", QString::fromStdString(serialNumber()))); return; } const QByteArray command = QByteArray("SCD PASSWD --nullpin ") + pinRef; ReaderStatus::mutableInstance()->startSimpleTransaction(nksCard, command, dialog, resultSlot); } void slotNksPinRequested() { setInitialPin("PW1.CH", "setNksPinSettingResult"); } void slotSigGPinRequested() { setInitialPin("PW1.CH.SIG", "setSigGPinSettingResult"); } void slotDialogRejected() { if (dialog->isComplete()) { slotDialogAccepted(); } else { canceled(); } } void slotDialogAccepted() { ReaderStatus::mutableInstance()->updateStatus(); finished(); } private: mutable QPointer dialog; }; SetInitialPinCommand::Private *SetInitialPinCommand::d_func() { return static_cast(d.get()); } const SetInitialPinCommand::Private *SetInitialPinCommand::d_func() const { return static_cast(d.get()); } #define q q_func() #define d d_func() SetInitialPinCommand::Private::Private(SetInitialPinCommand *qq, const std::string &serialNumber) : CardCommand::Private(qq, serialNumber, nullptr), dialog() { } SetInitialPinCommand::Private::~Private() {} SetInitialPinCommand::SetInitialPinCommand(const std::string &serialNumber) : CardCommand(new Private(this, serialNumber)) { d->init(); } SetInitialPinCommand::~SetInitialPinCommand() {} QDialog *SetInitialPinCommand::dialog() const { d->ensureDialogCreated(); return d->dialog; } void SetInitialPinCommand::doStart() { d->ensureDialogCreated(); const auto nksCard = ReaderStatus::instance()->getCard(d->serialNumber()); if (!nksCard) { d->error(i18n("Failed to find the NetKey card with the serial number: %1", QString::fromStdString(d->serialNumber()))); d->dialog->close(); finished(); return; } const std::vector pinStates = nksCard->pinStates(); d->dialog->setNksPinPresent(pinStates.size() >= 1 && pinStates[0] != Card::NullPin); d->dialog->setSigGPinPresent(pinStates.size() >= 3 && pinStates[2] != Card::NullPin); d->ensureDialogVisible(); } void SetInitialPinCommand::doCancel() { if (d->dialog) { d->dialog->close(); } } #undef q_func #undef d_func #include "moc_setinitialpincommand.cpp" diff --git a/src/commands/setpivcardapplicationadministrationkeycommand.cpp b/src/commands/setpivcardapplicationadministrationkeycommand.cpp index b8f07e8a3..9791814ec 100644 --- a/src/commands/setpivcardapplicationadministrationkeycommand.cpp +++ b/src/commands/setpivcardapplicationadministrationkeycommand.cpp @@ -1,220 +1,220 @@ /* commands/setpivcardapplicationadministrationkeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include "setpivcardapplicationadministrationkeycommand.h" #include "cardcommand_p.h" #include "smartcard/pivcard.h" #include "smartcard/readerstatus.h" #include "commands/authenticatepivcardapplicationcommand.h" #include "dialogs/pivcardapplicationadministrationkeyinputdialog.h" #include #include #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Dialogs; using namespace Kleo::SmartCard; using namespace GpgME; class SetPIVCardApplicationAdministrationKeyCommand::Private : public CardCommand::Private { friend class ::Kleo::Commands::SetPIVCardApplicationAdministrationKeyCommand; SetPIVCardApplicationAdministrationKeyCommand *q_func() const { return static_cast(q); } public: explicit Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p); - ~Private(); + ~Private() override; void init(); private: void slotDialogAccepted(); void slotDialogRejected(); void slotResult(const Error &err); private: void authenticate(); void authenticationFinished(); void authenticationCanceled(); void setAdminKey(); void ensureDialogCreated(); private: QByteArray newAdminKey; QPointer dialog; bool hasBeenCanceled = false; }; SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func() { return static_cast(d.get()); } const SetPIVCardApplicationAdministrationKeyCommand::Private *SetPIVCardApplicationAdministrationKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SetPIVCardApplicationAdministrationKeyCommand::Private::Private(SetPIVCardApplicationAdministrationKeyCommand *qq, const std::string &serialNumber, QWidget *p) : CardCommand::Private(qq, serialNumber, p) , dialog() { } SetPIVCardApplicationAdministrationKeyCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::Private::~Private()"; } SetPIVCardApplicationAdministrationKeyCommand::SetPIVCardApplicationAdministrationKeyCommand(const std::string &serialNumber, QWidget *p) : CardCommand(new Private(this, serialNumber, p)) { d->init(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::init() { } SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::~SetPIVCardApplicationAdministrationKeyCommand()"; } void SetPIVCardApplicationAdministrationKeyCommand::doStart() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::doStart()"; d->authenticate(); } void SetPIVCardApplicationAdministrationKeyCommand::doCancel() { } void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticate() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticate()"; auto cmd = new AuthenticatePIVCardApplicationCommand(serialNumber(), parentWidgetOrView()); cmd->setPrompt(i18n("Please enter the old PIV Card Application Administration Key in hex-encoded form.")); connect(cmd, &AuthenticatePIVCardApplicationCommand::finished, q, [this]() { authenticationFinished(); }); connect(cmd, &AuthenticatePIVCardApplicationCommand::canceled, q, [this]() { authenticationCanceled(); }); cmd->start(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationFinished() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationFinished()"; if (!hasBeenCanceled) { setAdminKey(); } } void SetPIVCardApplicationAdministrationKeyCommand::Private::authenticationCanceled() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::authenticationCanceled()"; hasBeenCanceled = true; canceled(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::setAdminKey() { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::setAdminKey()"; ensureDialogCreated(); Q_ASSERT(dialog); dialog->show(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new PIVCardApplicationAdministrationKeyInputDialog(parentWidgetOrView()); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setLabelText(newAdminKey.isEmpty() ? i18n("Please enter the new PIV Card Application Administration Key in hex-encoded form. " "The key needs to consist of 24 bytes, i.e. 48 hex-characters.") : i18n("Please enter the new PIV Card Application Administration Key again.")); connect(dialog, SIGNAL(accepted()), q, SLOT(slotDialogAccepted())); connect(dialog, SIGNAL(rejected()), q, SLOT(slotDialogRejected())); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogAccepted() { if (newAdminKey.isEmpty()) { newAdminKey = dialog->adminKey(); dialog = nullptr; setAdminKey(); return; } const QByteArray newAdminKey2 = dialog->adminKey(); if (newAdminKey != newAdminKey2) { error(i18nc("@info", "The two keys you have entered do not match. Please retry."), i18nc("@title", "Error")); newAdminKey.clear(); dialog = nullptr; setAdminKey(); return; } auto pivCard = ReaderStatus::instance()->getCard(serialNumber()); if (!pivCard) { error(i18n("Failed to find the PIV card with the serial number: %1", QString::fromStdString(serialNumber()))); finished(); return; } const QByteArray plusPercentEncodedAdminKey = newAdminKey.toPercentEncoding().replace(' ', '+'); const QByteArray command = QByteArray("SCD SETATTR SET-ADM-KEY ") + plusPercentEncodedAdminKey; ReaderStatus::mutableInstance()->startSimpleTransaction(pivCard, command, q, "slotResult"); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotDialogRejected() { finished(); } void SetPIVCardApplicationAdministrationKeyCommand::Private::slotResult(const GpgME::Error& err) { qCDebug(KLEOPATRA_LOG) << "SetPIVCardApplicationAdministrationKeyCommand::slotResult():" << err.asString() << "(" << err.code() << ")"; if (err) { error(i18nc("@info", "Setting the PIV Card Application Administration Key failed: %1", QString::fromLatin1(err.asString())), i18nc("@title", "Error")); } else if (!err.isCanceled()) { information(i18nc("@info", "PIV Card Application Administration Key set successfully."), i18nc("@title", "Success")); ReaderStatus::mutableInstance()->updateStatus(); } finished(); } #undef d #undef q #include "moc_setpivcardapplicationadministrationkeycommand.cpp" diff --git a/src/commands/signclipboardcommand.cpp b/src/commands/signclipboardcommand.cpp index 8bfbe1421..299ec18e7 100644 --- a/src/commands/signclipboardcommand.cpp +++ b/src/commands/signclipboardcommand.cpp @@ -1,177 +1,177 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/signclipboardcommand.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 "signclipboardcommand.h" #ifndef QT_NO_CLIPBOARD #include "command_p.h" #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class SignClipboardCommand::Private : public Command::Private { friend class ::Kleo::Commands::SignClipboardCommand; SignClipboardCommand *q_func() const { return static_cast(q); } public: explicit Private(SignClipboardCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; void init(); private: void slotSignersResolved(); void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: std::shared_ptr shared_qq; std::shared_ptr input; SignEMailController controller; }; SignClipboardCommand::Private *SignClipboardCommand::d_func() { return static_cast(d.get()); } const SignClipboardCommand::Private *SignClipboardCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SignClipboardCommand::Private::Private(SignClipboardCommand *qq, KeyListController *c) : Command::Private(qq, c), shared_qq(qq, [](SignClipboardCommand*){}), input(), controller(SignEMailController::ClipboardMode) { } SignClipboardCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } SignClipboardCommand::SignClipboardCommand(GpgME::Protocol protocol, KeyListController *c) : Command(new Private(this, c)) { d->init(); d->controller.setProtocol(protocol); } SignClipboardCommand::SignClipboardCommand(GpgME::Protocol protocol, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->controller.setProtocol(protocol); } void SignClipboardCommand::Private::init() { controller.setExecutionContext(shared_qq); controller.setDetachedSignature(false); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } SignClipboardCommand::~SignClipboardCommand() { qCDebug(KLEOPATRA_LOG); } // static bool SignClipboardCommand::canSignCurrentClipboard() { if (const QClipboard *clip = QApplication::clipboard()) if (const QMimeData *mime = clip->mimeData()) { return mime->hasText(); } return false; } void SignClipboardCommand::doStart() { try { // snapshot clipboard content here, in case it's being changed... d->input = Input::createFromClipboard(); connect(&d->controller, SIGNAL(signersResolved()), this, SLOT(slotSignersResolved())); d->controller.startResolveSigners(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Sign Clipboard Error")); d->finished(); } } void SignClipboardCommand::Private::slotSignersResolved() { try { controller.setInputAndOutput(input, Output::createFromClipboard()); input.reset(); // no longer needed, so don't keep a reference controller.start(); } catch (const std::exception &e) { information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Sign Clipboard Error")); finished(); } } void SignClipboardCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } #undef d #undef q #include "moc_signclipboardcommand.cpp" #endif // QT_NO_CLIPBOARD diff --git a/src/commands/signencryptfilescommand.cpp b/src/commands/signencryptfilescommand.cpp index 75f69e1a8..a4436841e 100644 --- a/src/commands/signencryptfilescommand.cpp +++ b/src/commands/signencryptfilescommand.cpp @@ -1,291 +1,291 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/signencryptfilescommand.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 "signencryptfilescommand.h" #include "command_p.h" #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace Kleo::Crypto; class SignEncryptFilesCommand::Private : public Command::Private { friend class ::Kleo::Commands::SignEncryptFilesCommand; SignEncryptFilesCommand *q_func() const { return static_cast(q); } public: explicit Private(SignEncryptFilesCommand *qq, KeyListController *c); - ~Private(); + ~Private() override; QStringList selectFiles() const; void init(); private: void slotControllerDone() { finished(); } void slotControllerError(int, const QString &) { finished(); } private: QStringList files; std::shared_ptr shared_qq; SignEncryptFilesController controller; }; SignEncryptFilesCommand::Private *SignEncryptFilesCommand::d_func() { return static_cast(d.get()); } const SignEncryptFilesCommand::Private *SignEncryptFilesCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() SignEncryptFilesCommand::Private::Private(SignEncryptFilesCommand *qq, KeyListController *c) : Command::Private(qq, c), files(), shared_qq(qq, [](SignEncryptFilesCommand*){}), controller() { controller.setOperationMode(SignEncryptFilesController::SignSelected | SignEncryptFilesController::EncryptSelected | SignEncryptFilesController::ArchiveAllowed); } SignEncryptFilesCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); } SignEncryptFilesCommand::SignEncryptFilesCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } SignEncryptFilesCommand::SignEncryptFilesCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } SignEncryptFilesCommand::SignEncryptFilesCommand(const QStringList &files, KeyListController *c) : Command(new Private(this, c)) { d->init(); d->files = files; } SignEncryptFilesCommand::SignEncryptFilesCommand(const QStringList &files, QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); d->files = files; } void SignEncryptFilesCommand::Private::init() { controller.setExecutionContext(shared_qq); connect(&controller, SIGNAL(done()), q, SLOT(slotControllerDone())); connect(&controller, SIGNAL(error(int,QString)), q, SLOT(slotControllerError(int,QString))); } SignEncryptFilesCommand::~SignEncryptFilesCommand() { qCDebug(KLEOPATRA_LOG); } void SignEncryptFilesCommand::setFiles(const QStringList &files) { d->files = files; } void SignEncryptFilesCommand::setSigningPolicy(Policy policy) { unsigned int mode = d->controller.operationMode(); mode &= ~SignEncryptFilesController::SignMask; switch (policy) { case NoPolicy: case Allow: mode |= SignEncryptFilesController::SignAllowed; break; case Deny: mode |= SignEncryptFilesController::SignDisallowed; break; case Force: mode |= SignEncryptFilesController::SignSelected; break; } try { d->controller.setOperationMode(mode); } catch (...) {} } Policy SignEncryptFilesCommand::signingPolicy() const { const unsigned int mode = d->controller.operationMode(); switch (mode & SignEncryptFilesController::SignMask) { default: Q_ASSERT(!"This should not happen!"); return NoPolicy; case SignEncryptFilesController::SignAllowed: return Allow; case SignEncryptFilesController::SignSelected: return Force; case SignEncryptFilesController::SignDisallowed: return Deny; } } void SignEncryptFilesCommand::setEncryptionPolicy(Policy policy) { unsigned int mode = d->controller.operationMode(); mode &= ~SignEncryptFilesController::EncryptMask; switch (policy) { case NoPolicy: case Allow: mode |= SignEncryptFilesController::EncryptAllowed; break; case Deny: mode |= SignEncryptFilesController::EncryptDisallowed; break; case Force: mode |= SignEncryptFilesController::EncryptSelected; break; } try { d->controller.setOperationMode(mode); } catch (...) {} } Policy SignEncryptFilesCommand::encryptionPolicy() const { const unsigned int mode = d->controller.operationMode(); switch (mode & SignEncryptFilesController::EncryptMask) { default: Q_ASSERT(!"This should not happen!"); return NoPolicy; case SignEncryptFilesController::EncryptAllowed: return Allow; case SignEncryptFilesController::EncryptSelected: return Force; case SignEncryptFilesController::EncryptDisallowed: return Deny; } } void SignEncryptFilesCommand::setArchivePolicy(Policy policy) { unsigned int mode = d->controller.operationMode(); mode &= ~SignEncryptFilesController::ArchiveMask; switch (policy) { case NoPolicy: case Allow: mode |= SignEncryptFilesController::ArchiveAllowed; break; case Deny: mode |= SignEncryptFilesController::ArchiveDisallowed; break; case Force: mode |= SignEncryptFilesController::ArchiveForced; break; } d->controller.setOperationMode(mode); } Policy SignEncryptFilesCommand::archivePolicy() const { const unsigned int mode = d->controller.operationMode(); switch (mode & SignEncryptFilesController::ArchiveMask) { case SignEncryptFilesController::ArchiveAllowed: return Allow; case SignEncryptFilesController::ArchiveForced: return Force; case SignEncryptFilesController::ArchiveDisallowed: return Deny; default: Q_ASSERT(!"This should not happen!"); return NoPolicy; } } void SignEncryptFilesCommand::setProtocol(GpgME::Protocol proto) { d->controller.setProtocol(proto); } GpgME::Protocol SignEncryptFilesCommand::protocol() const { return d->controller.protocol(); } void SignEncryptFilesCommand::doStart() { try { if (d->files.empty()) { d->files = selectFiles(); } if (d->files.empty()) { d->finished(); return; } d->controller.setFiles(d->files); d->controller.start(); } catch (const std::exception &e) { d->information(i18n("An error occurred: %1", QString::fromLocal8Bit(e.what())), i18n("Sign/Encrypt Files Error")); d->finished(); } } void SignEncryptFilesCommand::doCancel() { qCDebug(KLEOPATRA_LOG); d->controller.cancel(); } QStringList SignEncryptFilesCommand::selectFiles() const { return FileDialog::getOpenFileNames(d->parentWidgetOrView(), i18n("Select One or More Files to Sign and/or Encrypt"), QStringLiteral("enc")); } #undef d #undef q #include "moc_signencryptfilescommand.cpp" diff --git a/src/conf/appearanceconfigwidget.h b/src/conf/appearanceconfigwidget.h index c138f055b..0fc20c6ff 100644 --- a/src/conf/appearanceconfigwidget.h +++ b/src/conf/appearanceconfigwidget.h @@ -1,61 +1,61 @@ /* appearanceconfigwidget.h This file is part of kleopatra, the KDE key manager SPDX-FileCopyrightText: 2002, 2004, 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2002, 2003 Marc Mutz SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace Kleo { namespace Config { class AppearanceConfigWidget : public QWidget { Q_OBJECT public: explicit AppearanceConfigWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~AppearanceConfigWidget(); + ~AppearanceConfigWidget() override; public Q_SLOTS: void load(); void save(); void defaults(); Q_SIGNALS: void changed(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotIconClicked()) #ifndef QT_NO_COLORDIALOG Q_PRIVATE_SLOT(d, void slotForegroundClicked()) Q_PRIVATE_SLOT(d, void slotBackgroundClicked()) #endif #ifndef QT_NO_FONTDIALOG Q_PRIVATE_SLOT(d, void slotFontClicked()) #endif Q_PRIVATE_SLOT(d, void slotSelectionChanged()) Q_PRIVATE_SLOT(d, void slotDefaultClicked()) Q_PRIVATE_SLOT(d, void slotItalicToggled(bool)) Q_PRIVATE_SLOT(d, void slotBoldToggled(bool)) Q_PRIVATE_SLOT(d, void slotStrikeOutToggled(bool)) Q_PRIVATE_SLOT(d, void slotTooltipValidityChanged(bool)) Q_PRIVATE_SLOT(d, void slotTooltipDetailsChanged(bool)) Q_PRIVATE_SLOT(d, void slotTooltipOwnerChanged(bool)) Q_PRIVATE_SLOT(d, void slotUseTagsChanged(bool)) }; } } diff --git a/src/conf/smimevalidationconfigurationwidget.h b/src/conf/smimevalidationconfigurationwidget.h index a6f0d60c3..d9208483e 100644 --- a/src/conf/smimevalidationconfigurationwidget.h +++ b/src/conf/smimevalidationconfigurationwidget.h @@ -1,44 +1,44 @@ /* -*- mode: c++; c-basic-offset:4 -*- conf/smimevalidationconfigurationwidget.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 #include namespace Kleo { namespace Config { class SMimeValidationConfigurationWidget : public QWidget { Q_OBJECT public: explicit SMimeValidationConfigurationWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SMimeValidationConfigurationWidget(); + ~SMimeValidationConfigurationWidget() override; public Q_SLOTS: void load(); void save() const; void defaults(); Q_SIGNALS: void changed(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void enableDisableActions()) }; } } diff --git a/src/crypto/autodecryptverifyfilescontroller.h b/src/crypto/autodecryptverifyfilescontroller.h index 819d41a5d..88890479d 100644 --- a/src/crypto/autodecryptverifyfilescontroller.h +++ b/src/crypto/autodecryptverifyfilescontroller.h @@ -1,57 +1,57 @@ /* -*- mode: c++; c-basic-offset:4 -*- autodecryptverifyfilescontroller.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "crypto/decryptverifyfilescontroller.h" #include #include #include namespace Kleo { namespace Crypto { class AutoDecryptVerifyFilesController : public DecryptVerifyFilesController { Q_OBJECT public: explicit AutoDecryptVerifyFilesController(QObject *parent = nullptr); explicit AutoDecryptVerifyFilesController(const std::shared_ptr &ctx, QObject *parent = nullptr); - ~AutoDecryptVerifyFilesController(); + ~AutoDecryptVerifyFilesController() override; void setFiles(const QStringList &files) override; void setOperation(DecryptVerifyOperation op) override; DecryptVerifyOperation operation() const override; void start() override; public Q_SLOTS: void cancel() override; private: void doTaskDone(const Task *task, const std::shared_ptr &) override; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotDialogCanceled()) Q_PRIVATE_SLOT(d, void schedule()) }; } } diff --git a/src/crypto/controller.h b/src/crypto/controller.h index c1986d12d..ab3d51250 100644 --- a/src/crypto/controller.h +++ b/src/crypto/controller.h @@ -1,66 +1,66 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/controller.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 #include #include #include #include namespace Kleo { namespace Crypto { class Controller : public QObject, protected ExecutionContextUser { Q_OBJECT public: explicit Controller(QObject *parent = nullptr); explicit Controller(const std::shared_ptr &cmd, QObject *parent = nullptr); - ~Controller(); + ~Controller() override; using ExecutionContextUser::setExecutionContext; Q_SIGNALS: void progress(int current, int total, const QString &what); protected: void emitDoneOrError(); void setLastError(int err, const QString &details); void connectTask(const std::shared_ptr &task); virtual void doTaskDone(const Task *task, const std::shared_ptr &result); protected Q_SLOTS: void taskDone(const std::shared_ptr &); Q_SIGNALS: #ifndef Q_MOC_RUN # ifndef DOXYGEN_SHOULD_SKIP_THIS private: // don't tell moc or doxygen, but those signals are in fact private # endif #endif void error(int err, const QString &details); void done(); private: class Private; kdtools::pimpl_ptr d; }; } } diff --git a/src/crypto/createchecksumscontroller.cpp b/src/crypto/createchecksumscontroller.cpp index dee5aa2b3..dcd0fbc8d 100644 --- a/src/crypto/createchecksumscontroller.cpp +++ b/src/crypto/createchecksumscontroller.cpp @@ -1,719 +1,719 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/createchecksumscontroller.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "createchecksumscontroller.h" #include #include #include #include #include #include #include #include "kleopatra_debug.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; namespace { class ResultDialog : public QDialog { Q_OBJECT public: ResultDialog(const QStringList &created, const QStringList &errors, QWidget *parent = nullptr, Qt::WindowFlags f = {}) : QDialog(parent, f), createdLB(created.empty() ? i18nc("@info", "No checksum files have been created.") : i18nc("@info", "These checksum files have been successfully created:"), this), createdLW(this), errorsLB(errors.empty() ? i18nc("@info", "There were no errors.") : i18nc("@info", "The following errors were encountered:"), this), errorsLW(this), buttonBox(QDialogButtonBox::Ok, Qt::Horizontal, this), vlay(this) { KDAB_SET_OBJECT_NAME(createdLB); KDAB_SET_OBJECT_NAME(createdLW); KDAB_SET_OBJECT_NAME(errorsLB); KDAB_SET_OBJECT_NAME(errorsLW); KDAB_SET_OBJECT_NAME(buttonBox); KDAB_SET_OBJECT_NAME(vlay); createdLW.addItems(created); QRect r; for (int i = 0; i < created.size(); ++i) { r = r.united(createdLW.visualRect(createdLW.model()->index(0, i))); } createdLW.setMinimumWidth(qMin(1024, r.width() + 4 * createdLW.frameWidth())); errorsLW.addItems(errors); vlay.addWidget(&createdLB); vlay.addWidget(&createdLW, 1); vlay.addWidget(&errorsLB); vlay.addWidget(&errorsLW, 1); vlay.addWidget(&buttonBox); if (created.empty()) { createdLW.hide(); } if (errors.empty()) { errorsLW.hide(); } connect(&buttonBox, &QDialogButtonBox::accepted, this, &ResultDialog::accept); connect(&buttonBox, &QDialogButtonBox::rejected, this, &ResultDialog::reject); readConfig(); } - ~ResultDialog() + ~ResultDialog() override { writeConfig(); } void readConfig() { KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog"); const QSize size = dialog.readEntry("Size", QSize(600, 400)); if (size.isValid()) { resize(size); } } void writeConfig() { KConfigGroup dialog(KSharedConfig::openStateConfig(), "ResultDialog"); dialog.writeEntry("Size", size()); dialog.sync(); } private: QLabel createdLB; QListWidget createdLW; QLabel errorsLB; QListWidget errorsLW; QDialogButtonBox buttonBox; QVBoxLayout vlay; }; } #ifdef Q_OS_UNIX static const bool HAVE_UNIX = true; #else static const bool HAVE_UNIX = false; #endif static const Qt::CaseSensitivity fs_cs = HAVE_UNIX ? Qt::CaseSensitive : Qt::CaseInsensitive; // can we use QAbstractFileEngine::caseSensitive()? static QStringList fs_sort(QStringList l) { std::sort(l.begin(), l.end(), [](const QString &lhs, const QString &rhs) { return QString::compare(lhs, rhs, fs_cs) < 0; }); return l; } static QStringList fs_intersect(QStringList l1, QStringList l2) { fs_sort(l1); fs_sort(l2); QStringList result; std::set_intersection(l1.begin(), l1.end(), l2.begin(), l2.end(), std::back_inserter(result), [](const QString &lhs, const QString &rhs) { return QString::compare(lhs, rhs, fs_cs) < 0; }); return result; } static QList get_patterns(const std::vector< std::shared_ptr > &checksumDefinitions) { QList result; for (const std::shared_ptr &cd : checksumDefinitions) if (cd) { const auto patterns = cd->patterns(); for (const QString &pattern : patterns) { result.push_back(QRegExp(pattern, fs_cs)); } } return result; } namespace { struct matches_any : std::unary_function { const QList m_regexps; explicit matches_any(const QList ®exps) : m_regexps(regexps) {} bool operator()(const QString &s) const { return std::any_of(m_regexps.cbegin(), m_regexps.cend(), [s](const QRegExp &rx) { return rx.exactMatch(s); }); } }; } class CreateChecksumsController::Private : public QThread { Q_OBJECT friend class ::Kleo::Crypto::CreateChecksumsController; CreateChecksumsController *const q; public: explicit Private(CreateChecksumsController *qq); ~Private() override; Q_SIGNALS: void progress(int, int, const QString &); private: void slotOperationFinished() { #ifndef QT_NO_PROGRESSDIALOG if (progressDialog) { progressDialog->setValue(progressDialog->maximum()); progressDialog->close(); } #endif // QT_NO_PROGRESSDIALOG auto const dlg = new ResultDialog(created, errors); dlg->setAttribute(Qt::WA_DeleteOnClose); q->bringToForeground(dlg); if (!errors.empty()) q->setLastError(gpg_error(GPG_ERR_GENERAL), errors.join(QLatin1Char('\n'))); q->emitDoneOrError(); } void slotProgress(int current, int total, const QString &what) { qCDebug(KLEOPATRA_LOG) << "progress: " << current << "/" << total << ": " << qPrintable(what); #ifndef QT_NO_PROGRESSDIALOG if (!progressDialog) { return; } progressDialog->setMaximum(total); progressDialog->setValue(current); progressDialog->setLabelText(what); #endif // QT_NO_PROGRESSDIALOG } private: void run() override; private: #ifndef QT_NO_PROGRESSDIALOG QPointer progressDialog; #endif mutable QMutex mutex; const std::vector< std::shared_ptr > checksumDefinitions; std::shared_ptr checksumDefinition; QStringList files; QStringList errors, created; bool allowAddition; volatile bool canceled; }; CreateChecksumsController::Private::Private(CreateChecksumsController *qq) : q(qq), #ifndef QT_NO_PROGRESSDIALOG progressDialog(), #endif mutex(), checksumDefinitions(ChecksumDefinition::getChecksumDefinitions()), checksumDefinition(ChecksumDefinition::getDefaultChecksumDefinition(checksumDefinitions)), files(), errors(), created(), allowAddition(false), canceled(false) { connect(this, SIGNAL(progress(int,int,QString)), q, SLOT(slotProgress(int,int,QString))); connect(this, &Private::progress, q, &Controller::progress); connect(this, SIGNAL(finished()), q, SLOT(slotOperationFinished())); } CreateChecksumsController::Private::~Private() { qCDebug(KLEOPATRA_LOG); } CreateChecksumsController::CreateChecksumsController(QObject *p) : Controller(p), d(new Private(this)) { } CreateChecksumsController::CreateChecksumsController(const std::shared_ptr &ctx, QObject *p) : Controller(ctx, p), d(new Private(this)) { } CreateChecksumsController::~CreateChecksumsController() { qCDebug(KLEOPATRA_LOG); } void CreateChecksumsController::setFiles(const QStringList &files) { kleo_assert(!d->isRunning()); kleo_assert(!files.empty()); const QList patterns = get_patterns(d->checksumDefinitions); if (!std::all_of(files.cbegin(), files.cend(), matches_any(patterns)) && !std::none_of(files.cbegin(), files.cend(), matches_any(patterns))) { throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Create Checksums: input files must be either all checksum files or all files to be checksummed, not a mixture of both.")); } const QMutexLocker locker(&d->mutex); d->files = files; } void CreateChecksumsController::setAllowAddition(bool allow) { kleo_assert(!d->isRunning()); const QMutexLocker locker(&d->mutex); d->allowAddition = allow; } bool CreateChecksumsController::allowAddition() const { const QMutexLocker locker(&d->mutex); return d->allowAddition; } void CreateChecksumsController::start() { { const QMutexLocker locker(&d->mutex); #ifndef QT_NO_PROGRESSDIALOG d->progressDialog = new QProgressDialog(i18n("Initializing..."), i18n("Cancel"), 0, 0); applyWindowID(d->progressDialog); d->progressDialog->setAttribute(Qt::WA_DeleteOnClose); d->progressDialog->setMinimumDuration(1000); d->progressDialog->setWindowTitle(i18nc("@title:window", "Create Checksum Progress")); connect(d->progressDialog.data(), &QProgressDialog::canceled, this, &CreateChecksumsController::cancel); #endif // QT_NO_PROGRESSDIALOG d->canceled = false; d->errors.clear(); d->created.clear(); } d->start(); } void CreateChecksumsController::cancel() { qCDebug(KLEOPATRA_LOG); const QMutexLocker locker(&d->mutex); d->canceled = true; } namespace { struct Dir { QDir dir; QString sumFile; QStringList inputFiles; quint64 totalSize; std::shared_ptr checksumDefinition; }; } static QStringList remove_checksum_files(QStringList l, const QList &rxs) { QStringList::iterator end = l.end(); for (const QRegExp &rx : rxs) { end = std::remove_if(l.begin(), end, [rx](const QString &str) { return rx.exactMatch(str); }); } l.erase(end, l.end()); return l; } namespace { struct File { QString name; QByteArray checksum; bool binary; }; } static QString decode(const QString &encoded) { QString decoded; decoded.reserve(encoded.size()); bool shift = false; for (QChar ch : encoded) if (shift) { switch (ch.toLatin1()) { case '\\': decoded += QLatin1Char('\\'); break; case 'n': decoded += QLatin1Char('\n'); break; default: qCDebug(KLEOPATRA_LOG) << "invalid escape sequence" << '\\' << ch << "(interpreted as '" << ch << "')"; decoded += ch; break; } shift = false; } else { if (ch == QLatin1Char('\\')) { shift = true; } else { decoded += ch; } } return decoded; } static std::vector parse_sum_file(const QString &fileName) { std::vector files; QFile f(fileName); if (f.open(QIODevice::ReadOnly)) { QTextStream s(&f); QRegExp rx(QLatin1String("(\\?)([a-f0-9A-F]+) ([ *])([^\n]+)\n*")); while (!s.atEnd()) { const QString line = s.readLine(); if (rx.exactMatch(line)) { Q_ASSERT(!rx.cap(4).endsWith(QLatin1Char('\n'))); const File file = { rx.cap(1) == QLatin1String("\\") ? decode(rx.cap(4)) : rx.cap(4), rx.cap(2).toLatin1(), rx.cap(3) == QLatin1String("*"), }; files.push_back(file); } } } return files; } static quint64 aggregate_size(const QDir &dir, const QStringList &files) { quint64 n = 0; for (const QString &file : files) { n += QFileInfo(dir.absoluteFilePath(file)).size(); } return n; } static std::shared_ptr filename2definition(const QString &fileName, const std::vector< std::shared_ptr > &checksumDefinitions) { for (const std::shared_ptr &cd : checksumDefinitions) { if (cd) { const auto patterns = cd->patterns(); for (const QString &pattern : patterns) { if (QRegExp(pattern, fs_cs).exactMatch(fileName)) { return cd; } } } } return std::shared_ptr(); } static std::vector find_dirs_by_sum_files(const QStringList &files, bool allowAddition, const std::function &progress, const std::vector< std::shared_ptr > &checksumDefinitions) { const QList patterns = get_patterns(checksumDefinitions); std::vector dirs; dirs.reserve(files.size()); int i = 0; for (const QString &file : files) { const QFileInfo fi(file); const QDir dir = fi.dir(); const QStringList entries = remove_checksum_files(dir.entryList(QDir::Files), patterns); QStringList inputFiles; if (allowAddition) { inputFiles = entries; } else { const std::vector parsed = parse_sum_file(fi.absoluteFilePath()); QStringList oldInputFiles; oldInputFiles.reserve(parsed.size()); std::transform(parsed.cbegin(), parsed.cend(), std::back_inserter(oldInputFiles), std::mem_fn(&File::name)); inputFiles = fs_intersect(oldInputFiles, entries); } const Dir item = { dir, fi.fileName(), inputFiles, aggregate_size(dir, inputFiles), filename2definition(fi.fileName(), checksumDefinitions) }; dirs.push_back(item); if (progress) { progress(++i); } } return dirs; } namespace { struct less_dir : std::binary_function { bool operator()(const QDir &lhs, const QDir &rhs) const { return QString::compare(lhs.absolutePath(), rhs.absolutePath(), fs_cs) < 0; } }; } static std::vector find_dirs_by_input_files(const QStringList &files, const std::shared_ptr &checksumDefinition, bool allowAddition, const std::function &progress, const std::vector< std::shared_ptr > &checksumDefinitions) { Q_UNUSED(allowAddition) if (!checksumDefinition) { return std::vector(); } const QList patterns = get_patterns(checksumDefinitions); std::map dirs2files; // Step 1: sort files by the dir they're contained in: std::deque inputs(files.begin(), files.end()); int i = 0; while (!inputs.empty()) { const QString file = inputs.front(); inputs.pop_front(); const QFileInfo fi(file); if (fi.isDir()) { QDir dir(file); dirs2files[ dir ] = remove_checksum_files(dir.entryList(QDir::Files), patterns); const auto entryList = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); std::transform(entryList.cbegin(), entryList.cend(), std::inserter(inputs, inputs.begin()), [&dir](const QString &entry) { return dir.absoluteFilePath(entry); }); } else { dirs2files[fi.dir()].push_back(file); } if (progress) { progress(++i); } } // Step 2: convert into vector: std::vector dirs; dirs.reserve(dirs2files.size()); for (auto it = dirs2files.begin(), end = dirs2files.end(); it != end; ++it) { const QStringList inputFiles = remove_checksum_files(it->second, patterns); if (inputFiles.empty()) { continue; } const Dir dir = { it->first, checksumDefinition->outputFileName(), inputFiles, aggregate_size(it->first, inputFiles), checksumDefinition }; dirs.push_back(dir); if (progress) { progress(++i); } } return dirs; } static QString process(const Dir &dir, bool *fatal) { const QString absFilePath = dir.dir.absoluteFilePath(dir.sumFile); QTemporaryFile out; QProcess p; if (!out.open()) { return QStringLiteral("Failed to open Temporary file."); } p.setWorkingDirectory(dir.dir.absolutePath()); p.setStandardOutputFile(out.fileName()); const QString program = dir.checksumDefinition->createCommand(); dir.checksumDefinition->startCreateCommand(&p, dir.inputFiles); p.waitForFinished(); qCDebug(KLEOPATRA_LOG) << "[" << &p << "] Exit code " << p.exitCode(); if (p.exitStatus() != QProcess::NormalExit || p.exitCode() != 0) { if (fatal && p.error() == QProcess::FailedToStart) { *fatal = true; } if (p.error() == QProcess::UnknownError) return i18n("Error while running %1: %2", program, QString::fromLocal8Bit(p.readAllStandardError().trimmed().constData())); else { return i18n("Failed to execute %1: %2", program, p.errorString()); } } QFileInfo fi(absFilePath); if (!(fi.exists() && !QFile::remove(absFilePath)) && QFile::copy(out.fileName(), absFilePath)) { return QString(); } return xi18n("Failed to overwrite %1.", dir.sumFile); } namespace { static QDebug operator<<(QDebug s, const Dir &dir) { return s << "Dir(" << dir.dir << "->" << dir.sumFile << "<-(" << dir.totalSize << ')' << dir.inputFiles << ")\n"; } } void CreateChecksumsController::Private::run() { QMutexLocker locker(&mutex); const QStringList files = this->files; const std::vector< std::shared_ptr > checksumDefinitions = this->checksumDefinitions; const std::shared_ptr checksumDefinition = this->checksumDefinition; const bool allowAddition = this->allowAddition; locker.unlock(); QStringList errors; QStringList created; if (!checksumDefinition) { errors.push_back(i18n("No checksum programs defined.")); locker.relock(); this->errors = errors; return; } else { qCDebug(KLEOPATRA_LOG) << "using checksum-definition" << checksumDefinition->id(); } // // Step 1: build a list of work to do (no progress): // const QString scanning = i18n("Scanning directories..."); Q_EMIT progress(0, 0, scanning); const bool haveSumFiles = std::all_of(files.cbegin(), files.cend(), matches_any(get_patterns(checksumDefinitions))); const auto progressCb = [this, &scanning](int c) { Q_EMIT progress(c, 0, scanning); }; const std::vector dirs = haveSumFiles ? find_dirs_by_sum_files(files, allowAddition, progressCb, checksumDefinitions) : find_dirs_by_input_files(files, checksumDefinition, allowAddition, progressCb, checksumDefinitions); for (const Dir &dir : dirs) { qCDebug(KLEOPATRA_LOG) << dir; } if (!canceled) { Q_EMIT progress(0, 0, i18n("Calculating total size...")); const quint64 total = kdtools::accumulate_transform(dirs.cbegin(), dirs.cend(), std::mem_fn(&Dir::totalSize), Q_UINT64_C(0)); if (!canceled) { // // Step 2: perform work (with progress reporting): // // re-scale 'total' to fit into ints (wish QProgressDialog would use quint64...) const quint64 factor = total / std::numeric_limits::max() + 1; quint64 done = 0; for (const Dir &dir : dirs) { Q_EMIT progress(done / factor, total / factor, i18n("Checksumming (%2) in %1", dir.checksumDefinition->label(), dir.dir.path())); bool fatal = false; const QString error = process(dir, &fatal); if (!error.isEmpty()) { errors.push_back(error); } else { created.push_back(dir.dir.absoluteFilePath(dir.sumFile)); } done += dir.totalSize; if (fatal || canceled) { break; } } Q_EMIT progress(done / factor, total / factor, i18n("Done.")); } } locker.relock(); this->errors = errors; this->created = created; // mutex unlocked by QMutexLocker } #include "moc_createchecksumscontroller.cpp" #include "createchecksumscontroller.moc" diff --git a/src/crypto/createchecksumscontroller.h b/src/crypto/createchecksumscontroller.h index 1001ad77e..761a303df 100644 --- a/src/crypto/createchecksumscontroller.h +++ b/src/crypto/createchecksumscontroller.h @@ -1,55 +1,55 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/createchecksumscontroller.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include #include namespace Kleo { namespace Crypto { class CreateChecksumsController : public Controller { Q_OBJECT public: explicit CreateChecksumsController(QObject *parent = nullptr); explicit CreateChecksumsController(const std::shared_ptr &ctx, QObject *parent = nullptr); - ~CreateChecksumsController(); + ~CreateChecksumsController() override; void setAllowAddition(bool allow); bool allowAddition() const; void setFiles(const QStringList &files); void start(); public Q_SLOTS: void cancel(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotOperationFinished()) Q_PRIVATE_SLOT(d, void slotProgress(int, int, QString)) }; } } diff --git a/src/crypto/decryptverifytask.h b/src/crypto/decryptverifytask.h index 3bb452087..8a8d89cde 100644 --- a/src/crypto/decryptverifytask.h +++ b/src/crypto/decryptverifytask.h @@ -1,259 +1,259 @@ /* -*- 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); - virtual ~AbstractDecryptVerifyTask(); + ~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 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; bool hasError() const; int errorCode() 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; 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, int errCode, 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/gui/decryptverifyfilesdialog.h b/src/crypto/gui/decryptverifyfilesdialog.h index 6c5040af1..457d0fc0b 100644 --- a/src/crypto/gui/decryptverifyfilesdialog.h +++ b/src/crypto/gui/decryptverifyfilesdialog.h @@ -1,76 +1,76 @@ /* crypto/gui/decryptverifyfilesdialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include "crypto/task.h" #include class QVBoxLayout; class QProgressBar; template class QHash; class QLabel; namespace Kleo { class FileNameRequester; namespace Crypto { class TaskCollection; namespace Gui { class ResultListWidget; class DecryptVerifyFilesDialog : public QDialog { Q_OBJECT public: explicit DecryptVerifyFilesDialog(const std::shared_ptr &coll, QWidget *parent = nullptr); - ~DecryptVerifyFilesDialog(); + ~DecryptVerifyFilesDialog() override; void setOutputLocation(const QString &dir); QString outputLocation() const; protected Q_SLOTS: void progress(const QString &msg, int progress, int total); void started(const std::shared_ptr &result); void allDone(); void btnClicked(QAbstractButton *btn); void checkAccept(); protected: void readConfig(); void writeConfig(); protected: QLabel *labelForTag(const QString &tag); private: std::shared_ptr m_tasks; QProgressBar *m_progressBar; QHash m_progressLabelByTag; QVBoxLayout *m_progressLabelLayout; int m_lastErrorItemIndex; ResultListWidget *m_resultList; FileNameRequester *m_outputLocationFNR; QDialogButtonBox::StandardButton m_saveButton = QDialogButtonBox::NoButton; QDialogButtonBox *const m_buttonBox; }; } // namespace Gui } //namespace Crypto; } // namespace Kleo diff --git a/src/crypto/gui/decryptverifyoperationwidget.h b/src/crypto/gui/decryptverifyoperationwidget.h index 0191340e4..f061a23fd 100644 --- a/src/crypto/gui/decryptverifyoperationwidget.h +++ b/src/crypto/gui/decryptverifyoperationwidget.h @@ -1,69 +1,69 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/decryptverifyoperationwidget.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 namespace Kleo { class ArchiveDefinition; } namespace Kleo { namespace Crypto { namespace Gui { class DecryptVerifyOperationWidget : public QWidget { Q_OBJECT Q_ENUMS(Mode) Q_PROPERTY(Mode mode READ mode WRITE setMode) Q_PROPERTY(QString inputFileName READ inputFileName WRITE setInputFileName) Q_PROPERTY(QString signedDataFileName READ signedDataFileName WRITE setSignedDataFileName) public: explicit DecryptVerifyOperationWidget(QWidget *parent = nullptr); - ~DecryptVerifyOperationWidget(); + ~DecryptVerifyOperationWidget() override; enum Mode { VerifyDetachedWithSignature, VerifyDetachedWithSignedData, DecryptVerifyOpaque }; void setMode(Mode mode, const std::shared_ptr &ad); void setMode(Mode mode); Mode mode() const; void setInputFileName(const QString &name); QString inputFileName() const; void setSignedDataFileName(const QString &name); QString signedDataFileName() const; void setArchiveDefinitions(const std::vector< std::shared_ptr > &ads); std::shared_ptr selectedArchiveDefinition() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void enableDisableWidgets()) }; } } } diff --git a/src/crypto/gui/encryptemailwizard.h b/src/crypto/gui/encryptemailwizard.h index b57bbc8a5..69ed4c0fd 100644 --- a/src/crypto/gui/encryptemailwizard.h +++ b/src/crypto/gui/encryptemailwizard.h @@ -1,37 +1,37 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/encryptemailwizard.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 namespace Kleo { namespace Crypto { namespace Gui { class EncryptEMailWizard : public SignEncryptWizard { Q_OBJECT public: explicit EncryptEMailWizard(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); - ~EncryptEMailWizard(); + ~EncryptEMailWizard() override; bool quickMode() const; void setQuickMode(bool quick); private: class Private; kdtools::pimpl_ptr d; }; } } } diff --git a/src/crypto/gui/resolverecipientspage_p.h b/src/crypto/gui/resolverecipientspage_p.h index 9b5636150..6773bb247 100644 --- a/src/crypto/gui/resolverecipientspage_p.h +++ b/src/crypto/gui/resolverecipientspage_p.h @@ -1,107 +1,107 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resolverecipientspage_p.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 class QComboBox; class QLabel; class QListWidget; class QListWidgetItem; #include class QToolButton; class Kleo::Crypto::Gui::ResolveRecipientsPage::ListWidget : public QWidget { Q_OBJECT public: explicit ListWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); - ~ListWidget(); + ~ListWidget() override; void addEntry(const QString &id, const QString &name); void addEntry(const KMime::Types::Mailbox &mbox); void addEntry(const QString &id, const QString &name, const KMime::Types::Mailbox &mbox); void removeEntry(const QString &id); QStringList selectedEntries() const; void setCertificates(const QString &id, const std::vector &pgpCerts, const std::vector &cmsCerts); GpgME::Key selectedCertificate(const QString &id) const; GpgME::Key selectedCertificate(const QString &id, GpgME::Protocol prot) const; KMime::Types::Mailbox mailbox(const QString &id) const; QStringList identifiers() const; void setProtocol(GpgME::Protocol prot); void showSelectionDialog(const QString &id); enum Role { IdRole = Qt::UserRole }; Q_SIGNALS: void selectionChanged(); void completeChanged(); private Q_SLOTS: void onSelectionChange(); private: QListWidget *m_listWidget; QHash widgets; QHash items; GpgME::Protocol m_protocol; }; class Kleo::Crypto::Gui::ResolveRecipientsPage::ItemWidget : public QWidget { Q_OBJECT public: explicit ItemWidget(const QString &id, const QString &name, const KMime::Types::Mailbox &mbox, QWidget *parent = nullptr, Qt::WindowFlags flags = {}); - ~ItemWidget(); + ~ItemWidget() override; QString id() const; KMime::Types::Mailbox mailbox() const; void setCertificates(const std::vector &pgp, const std::vector &cms); GpgME::Key selectedCertificate() const; GpgME::Key selectedCertificate(GpgME::Protocol prot) const; std::vector certificates() const; void setProtocol(GpgME::Protocol protocol); void setSelected(bool selected); bool isSelected() const; public Q_SLOTS: void showSelectionDialog(); Q_SIGNALS: void changed(); private: void addCertificateToComboBox(const GpgME::Key &key); void resetCertificates(); void selectCertificateInComboBox(const GpgME::Key &key); void updateVisibility(); private: QString m_id; KMime::Types::Mailbox m_mailbox; QLabel *m_nameLabel; QLabel *m_certLabel; QComboBox *m_certCombo; QToolButton *m_selectButton; GpgME::Protocol m_protocol; QHash m_selectedCertificates; std::vector m_pgp, m_cms; bool m_selected; }; diff --git a/src/crypto/gui/resultitemwidget.h b/src/crypto/gui/resultitemwidget.h index b5b7ee4d5..e2e1346b9 100644 --- a/src/crypto/gui/resultitemwidget.h +++ b/src/crypto/gui/resultitemwidget.h @@ -1,58 +1,58 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultitemwidget.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 #include #include #include class QString; namespace Kleo { namespace Crypto { class Task; namespace Gui { class ResultItemWidget : public QWidget { Q_OBJECT public: explicit ResultItemWidget(const std::shared_ptr &result, QWidget *parent = nullptr, Qt::WindowFlags flags = {}); - ~ResultItemWidget(); + ~ResultItemWidget() override; bool hasErrorResult() const; void showCloseButton(bool show); public Q_SLOTS: void showAuditLog(); Q_SIGNALS: void linkActivated(const QString &link); void closeButtonClicked(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotLinkActivated(QString)) }; } } } diff --git a/src/crypto/gui/resultlistwidget.h b/src/crypto/gui/resultlistwidget.h index 0d4908c11..cbc904d5f 100644 --- a/src/crypto/gui/resultlistwidget.h +++ b/src/crypto/gui/resultlistwidget.h @@ -1,63 +1,63 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/resultlistwidget.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 #include #include #include class QString; namespace Kleo { namespace Crypto { class TaskCollection; namespace Gui { class ResultListWidget : public QWidget { Q_OBJECT public: explicit ResultListWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); - ~ResultListWidget(); + ~ResultListWidget() override; void setTaskCollection(const std::shared_ptr &coll); void addTaskCollection(const std::shared_ptr &coll); void setStandaloneMode(bool standalone); bool isComplete() const; unsigned int totalNumberOfTasks() const; unsigned int numberOfCompletedTasks() const; Q_SIGNALS: void linkActivated(const QString &link); void completeChanged(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void result(std::shared_ptr)) Q_PRIVATE_SLOT(d, void started(std::shared_ptr)) Q_PRIVATE_SLOT(d, void allTasksDone()) }; } } } diff --git a/src/crypto/gui/signemailwizard.h b/src/crypto/gui/signemailwizard.h index 7ab0c0e54..ad7f24541 100644 --- a/src/crypto/gui/signemailwizard.h +++ b/src/crypto/gui/signemailwizard.h @@ -1,41 +1,41 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signemailwizard.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 #include namespace Kleo { namespace Crypto { namespace Gui { class SignEMailWizard : public SignEncryptWizard { Q_OBJECT public: explicit SignEMailWizard(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SignEMailWizard(); + ~SignEMailWizard() override; bool quickMode() const; void setQuickMode(bool quick); private: class Private; kdtools::pimpl_ptr d; }; } } } diff --git a/src/crypto/gui/signencryptemailconflictdialog.h b/src/crypto/gui/signencryptemailconflictdialog.h index cf9eeda7a..c23b5a3dc 100644 --- a/src/crypto/gui/signencryptemailconflictdialog.h +++ b/src/crypto/gui/signencryptemailconflictdialog.h @@ -1,89 +1,89 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptemailconflictdialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include namespace GpgME { class Key; } namespace Kleo { namespace Crypto { class Sender; class Recipient; } } namespace Kleo { namespace Crypto { namespace Gui { class SignEncryptEMailConflictDialog : public QDialog { Q_OBJECT public: explicit SignEncryptEMailConflictDialog(QWidget *parent = nullptr); - ~SignEncryptEMailConflictDialog(); + ~SignEncryptEMailConflictDialog() override; // Inputs void setPresetProtocol(GpgME::Protocol proto); void setSubject(const QString &subject); void setSenders(const std::vector &senders); void setRecipients(const std::vector &recipients); void setSign(bool on); void setEncrypt(bool on); void setQuickMode(bool on); // To wrap up inputs: void pickProtocol(); void setConflict(bool conflict); // Intermediate bool isComplete() const; // Outputs GpgME::Protocol selectedProtocol() const; std::vector resolvedSigningKeys() const; std::vector resolvedEncryptionKeys() const; bool isQuickMode() const; private: Q_PRIVATE_SLOT(d, void slotCompleteChanged()) Q_PRIVATE_SLOT(d, void slotShowAllRecipientsToggled(bool)) Q_PRIVATE_SLOT(d, void slotProtocolChanged()) Q_PRIVATE_SLOT(d, void slotCertificateSelectionDialogRequested()) class Private; kdtools::pimpl_ptr d; }; } } } diff --git a/src/crypto/gui/signencryptfileswizard.h b/src/crypto/gui/signencryptfileswizard.h index 33af2e0aa..e91b2b331 100644 --- a/src/crypto/gui/signencryptfileswizard.h +++ b/src/crypto/gui/signencryptfileswizard.h @@ -1,104 +1,104 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signencryptfileswizard.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include #include namespace GpgME { class Key; } namespace Kleo { namespace Crypto { class TaskCollection; } } class ResultPage; class SigEncPage; namespace Kleo { class SignEncryptFilesWizard : public QWizard { Q_OBJECT public: enum KindNames { SignatureCMS, SignaturePGP, CombinedPGP, EncryptedPGP, EncryptedCMS, Directory }; explicit SignEncryptFilesWizard(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SignEncryptFilesWizard(); + ~SignEncryptFilesWizard() override; // Inputs void setSigningPreset(bool preset); void setSigningUserMutable(bool mut); void setEncryptionPreset(bool preset); void setEncryptionUserMutable(bool mut); void setArchiveForced(bool archive); void setArchiveMutable(bool archive); void setSingleFile(bool singleFile); void setOutputNames(const QMap &nameMap) const; QMap outputNames() const; void setTaskCollection(const std::shared_ptr &coll); // Outputs std::vector resolvedRecipients() const; std::vector resolvedSigners() const; bool encryptSymmetric() const; void setLabelText(const QString &label); protected: void readConfig(); void writeConfig(); Q_SIGNALS: void operationPrepared(); private Q_SLOTS: void slotCurrentIdChanged(int); private: SigEncPage *mSigEncPage = nullptr; ResultPage *mResultPage = nullptr; bool mSigningUserMutable = true; bool mEncryptionUserMutable = true; }; } diff --git a/src/crypto/gui/signingcertificateselectiondialog.h b/src/crypto/gui/signingcertificateselectiondialog.h index 985284b97..c89c2d04d 100644 --- a/src/crypto/gui/signingcertificateselectiondialog.h +++ b/src/crypto/gui/signingcertificateselectiondialog.h @@ -1,51 +1,51 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signingcertificateselectiondialog.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 template class QMap; namespace Kleo { namespace Crypto { namespace Gui { class SigningCertificateSelectionWidget; class SigningCertificateSelectionDialog : public QDialog { Q_OBJECT public: explicit SigningCertificateSelectionDialog(QWidget *parent = nullptr); - ~SigningCertificateSelectionDialog(); + ~SigningCertificateSelectionDialog() override; void setAllowedProtocols(const std::set &allowedProtocols); void setSelectedCertificates(const QMap &certificates); Q_REQUIRED_RESULT QMap selectedCertificates() const; Q_REQUIRED_RESULT bool rememberAsDefault() const; private: SigningCertificateSelectionWidget *const widget; }; } } } diff --git a/src/crypto/gui/signingcertificateselectionwidget.h b/src/crypto/gui/signingcertificateselectionwidget.h index 0fd380c60..f82536f1b 100644 --- a/src/crypto/gui/signingcertificateselectionwidget.h +++ b/src/crypto/gui/signingcertificateselectionwidget.h @@ -1,57 +1,57 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/signingcertificateselectionwidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2007, 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include template class QMap; namespace GpgME { class Key; } namespace Kleo { namespace Crypto { namespace Gui { class SigningCertificateSelectionWidget : public QWidget { Q_OBJECT public: explicit SigningCertificateSelectionWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SigningCertificateSelectionWidget(); + ~SigningCertificateSelectionWidget() override; void setAllowedProtocols(const std::set &allowedProtocols); void setAllowedProtocols(bool pgp, bool cms); void setSelectedCertificates(const QMap &certificates); void setSelectedCertificates(const GpgME::Key &pgp, const GpgME::Key &cms); QMap selectedCertificates() const; bool rememberAsDefault() const; private: class Private; kdtools::pimpl_ptr d; }; } } } diff --git a/src/crypto/gui/verifychecksumsdialog.h b/src/crypto/gui/verifychecksumsdialog.h index 1a6cae2a1..d5275ff44 100644 --- a/src/crypto/gui/verifychecksumsdialog.h +++ b/src/crypto/gui/verifychecksumsdialog.h @@ -1,64 +1,64 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/verifychecksumsdialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #ifndef QT_NO_DIRMODEL #include namespace Kleo { namespace Crypto { namespace Gui { class VerifyChecksumsDialog : public QDialog { Q_OBJECT Q_ENUMS(Status) public: explicit VerifyChecksumsDialog(QWidget *parent = nullptr); - ~VerifyChecksumsDialog(); + ~VerifyChecksumsDialog() override; enum Status { Unknown, OK, Failed, Error, NumStatii }; public Q_SLOTS: void setBaseDirectories(const QStringList &bases); void setProgress(int current, int total); void setStatus(const QString &file, Kleo::Crypto::Gui::VerifyChecksumsDialog::Status status); void setErrors(const QStringList &errors); void clearStatusInformation(); Q_SIGNALS: void canceled(); private: Q_PRIVATE_SLOT(d, void slotErrorButtonClicked()) class Private; kdtools::pimpl_ptr d; }; } } } Q_DECLARE_METATYPE(Kleo::Crypto::Gui::VerifyChecksumsDialog::Status) #endif // QT_NO_DIRMODEL diff --git a/src/crypto/gui/wizard.h b/src/crypto/gui/wizard.h index 3d10d1806..414c0a14c 100644 --- a/src/crypto/gui/wizard.h +++ b/src/crypto/gui/wizard.h @@ -1,78 +1,78 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/wizard.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 namespace Kleo { namespace Crypto { namespace Gui { class WizardPage; class Wizard : public QDialog { Q_OBJECT public: explicit Wizard(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~Wizard(); + ~Wizard() override; enum Page { InvalidPage = -1 }; void setPage(int id, WizardPage *page); const WizardPage *page(int id) const; WizardPage *page(int id); void setPageOrder(const std::vector &pages); void setPageVisible(int id, bool visible); void setCurrentPage(int id); int currentPage() const; const WizardPage *currentPageWidget() const; WizardPage *currentPageWidget(); bool canGoToPreviousPage() const; bool canGoToNextPage() const; public Q_SLOTS: void next(); void back(); Q_SIGNALS: void canceled(); protected: virtual void onNext(int currentId); virtual void onBack(int currentId); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void updateButtonStates()) Q_PRIVATE_SLOT(d, void updateHeader()) }; } } } diff --git a/src/crypto/gui/wizardpage.h b/src/crypto/gui/wizardpage.h index 5dd9c3cfd..03e3d4d2f 100644 --- a/src/crypto/gui/wizardpage.h +++ b/src/crypto/gui/wizardpage.h @@ -1,76 +1,76 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/gui/wizardpage.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 class KGuiItem; namespace Kleo { namespace Crypto { namespace Gui { class Wizard; class WizardPage : public QWidget { friend class ::Kleo::Crypto::Gui::Wizard; Q_OBJECT public: explicit WizardPage(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - virtual ~WizardPage(); + ~WizardPage() override; virtual bool isComplete() const = 0; bool isCommitPage() const; void setCommitPage(bool commitPage); bool autoAdvance() const; void setAutoAdvance(bool enabled); QString title() const; void setTitle(const QString &title); QString subTitle() const; void setSubTitle(const QString &subTitle); QString explanation() const; void setExplanation(const QString &explanation); KGuiItem customNextButton() const; void setCustomNextButton(const KGuiItem &item); Q_SIGNALS: void completeChanged(); void explanationChanged(); void titleChanged(); void subTitleChanged(); void autoAdvanceChanged(); void windowTitleChanged(const QString &title); protected: virtual void onNext(); private: class Private; kdtools::pimpl_ptr d; }; } } } diff --git a/src/crypto/task.h b/src/crypto/task.h index 5b6f63477..3f9848472 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(); + ~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); 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); 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); 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 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/crypto/taskcollection.h b/src/crypto/taskcollection.h index a241afa91..444c323e4 100644 --- a/src/crypto/taskcollection.h +++ b/src/crypto/taskcollection.h @@ -1,62 +1,62 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/taskcollection.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 #include #include #include #include namespace Kleo { namespace Crypto { class TaskCollection : public QObject { Q_OBJECT public: explicit TaskCollection(QObject *parent = nullptr); - ~TaskCollection(); + ~TaskCollection() override; std::vector > tasks() const; std::shared_ptr taskById(int id) const; void setTasks(const std::vector > &tasks); bool isEmpty() const; size_t size() const; int numberOfCompletedTasks() const; bool allTasksCompleted() const; bool errorOccurred() const; bool allTasksHaveErrors() const; Q_SIGNALS: void progress(const QString &msg, int processed, int total); void result(const std::shared_ptr &result); void started(const std::shared_ptr &task); void done(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void taskProgress(QString, int, int)) Q_PRIVATE_SLOT(d, void taskResult(std::shared_ptr)) Q_PRIVATE_SLOT(d, void taskStarted()) }; } } diff --git a/src/crypto/verifychecksumscontroller.h b/src/crypto/verifychecksumscontroller.h index ecd6a4938..1b1480b9a 100644 --- a/src/crypto/verifychecksumscontroller.h +++ b/src/crypto/verifychecksumscontroller.h @@ -1,55 +1,55 @@ /* -*- mode: c++; c-basic-offset:4 -*- crypto/verifychecksumscontroller.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #ifndef QT_NO_DIRMODEL #include #include #include #include #include namespace Kleo { namespace Crypto { class VerifyChecksumsController : public Controller { Q_OBJECT public: explicit VerifyChecksumsController(QObject *parent = nullptr); explicit VerifyChecksumsController(const std::shared_ptr &ctx, QObject *parent = nullptr); - ~VerifyChecksumsController(); + ~VerifyChecksumsController() override; void setFiles(const QStringList &files); void start(); public Q_SLOTS: void cancel(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotOperationFinished()) }; } } #endif // QT_NO_DIRMODEL diff --git a/src/dialogs/addemaildialog.h b/src/dialogs/addemaildialog.h index 74a36e816..ad6cd521a 100644 --- a/src/dialogs/addemaildialog.h +++ b/src/dialogs/addemaildialog.h @@ -1,40 +1,40 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/addemaildialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2019 g 10 Code GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class QString; namespace Kleo { namespace Dialogs { class AddEmailDialog : public QDialog { Q_OBJECT public: explicit AddEmailDialog(QWidget *parent = nullptr); - ~AddEmailDialog(); + ~AddEmailDialog() override; void setEmail(const QString &email); QString email() const; bool advancedSelected(); private: class Private; std::shared_ptr d; }; } } diff --git a/src/dialogs/adduseriddialog.h b/src/dialogs/adduseriddialog.h index 38c8c78a1..b9d3ea630 100644 --- a/src/dialogs/adduseriddialog.h +++ b/src/dialogs/adduseriddialog.h @@ -1,50 +1,50 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/addUserIDdialog.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 #include class QString; namespace Kleo { namespace Dialogs { class AddUserIDDialog : public QDialog { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString email READ email WRITE setEmail) Q_PROPERTY(QString comment READ comment WRITE setComment) public: explicit AddUserIDDialog(QWidget *parent = nullptr); - ~AddUserIDDialog(); + ~AddUserIDDialog() override; void setName(const QString &name); QString name() const; void setEmail(const QString &email); QString email() const; void setComment(const QString &comment); QString comment() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotUserIDChanged()) }; } } diff --git a/src/dialogs/certifycertificatedialog.h b/src/dialogs/certifycertificatedialog.h index ca0fbfd95..7306ccacb 100644 --- a/src/dialogs/certifycertificatedialog.h +++ b/src/dialogs/certifycertificatedialog.h @@ -1,63 +1,63 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/signcertificatedialog.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 #include #include #include namespace Kleo { class CertifyWidget; class CertifyCertificateDialog : public QDialog { Q_OBJECT public: explicit CertifyCertificateDialog(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~CertifyCertificateDialog(); + ~CertifyCertificateDialog() override; bool exportableCertificationSelected() const; bool trustSignatureSelected() const; QString trustSignatureDomain() const; bool nonRevocableCertificationSelected() const; void setSelectedUserIDs(const std::vector &uids); std::vector selectedUserIDs() const; GpgME::Key selectedSecretKey() const; bool sendToServer() const; unsigned int selectedCheckLevel() const; void setCertificateToCertify(const GpgME::Key &key); QString tags() const; QDate expirationDate() const; public Q_SLOTS: void accept() override; private: CertifyWidget *mCertWidget; }; } diff --git a/src/dialogs/exportdialog.h b/src/dialogs/exportdialog.h index e4a14bb0d..547cb37e9 100644 --- a/src/dialogs/exportdialog.h +++ b/src/dialogs/exportdialog.h @@ -1,56 +1,56 @@ /* SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace GpgME { class Key; class Subkey; class Error; } namespace Kleo { class ExportWidget : public QWidget { Q_OBJECT public: explicit ExportWidget(QWidget *parent = nullptr); - ~ExportWidget(); + ~ExportWidget() override; void setKey(const GpgME::Key &key, unsigned int flags = 0); void setKey(const GpgME::Subkey &key, unsigned int flags = 0); GpgME::Key key() const; private Q_SLOTS: void exportResult(const GpgME::Error &err, const QByteArray &data); private: class Private; const QScopedPointer d; }; class ExportDialog : public QDialog { Q_OBJECT public: explicit ExportDialog(QWidget *parent = nullptr); - ~ExportDialog(); + ~ExportDialog() override; void setKey(const GpgME::Key &key, unsigned int flags = 0); void setKey(const GpgME::Subkey &key, unsigned int flags = 0); GpgME::Key key() const; private: ExportWidget *mWidget; }; } // namespace Kleo diff --git a/src/dialogs/ownertrustdialog.h b/src/dialogs/ownertrustdialog.h index ed06e8a63..0982b58e1 100644 --- a/src/dialogs/ownertrustdialog.h +++ b/src/dialogs/ownertrustdialog.h @@ -1,50 +1,50 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/ownertrustdialog.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 #include #include namespace Kleo { namespace Dialogs { class OwnerTrustDialog : public QDialog { Q_OBJECT public: explicit OwnerTrustDialog(QWidget *parent = nullptr); - ~OwnerTrustDialog(); + ~OwnerTrustDialog() override; void setFormattedCertificateName(const QString &formatted); QString formattedCertificateName() const; void setHasSecretKey(bool secret); bool hasSecretKey() const; void setAdvancedMode(bool advanced); bool isAdvancedMode() const; void setOwnerTrust(GpgME::Key::OwnerTrust); GpgME::Key::OwnerTrust ownerTrust() const; private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotTrustLevelChanged()) }; } } diff --git a/src/dialogs/selftestdialog.h b/src/dialogs/selftestdialog.h index 25f89a79f..fdda06aa6 100644 --- a/src/dialogs/selftestdialog.h +++ b/src/dialogs/selftestdialog.h @@ -1,59 +1,59 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/selftestdialog.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 #include #include #include namespace Kleo { class SelfTest; namespace Dialogs { class SelfTestDialog : public QDialog { Q_OBJECT Q_PROPERTY(bool runAtStartUp READ runAtStartUp WRITE setRunAtStartUp) public: explicit SelfTestDialog(QWidget *parent = nullptr, Qt::WindowFlags f = {}); explicit SelfTestDialog(const std::vector> &tests, QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SelfTestDialog(); + ~SelfTestDialog() override; void setAutomaticMode(bool automatic); void addSelfTest(const std::shared_ptr &test); void addSelfTests(const std::vector> &tests); void setRunAtStartUp(bool run); bool runAtStartUp() const; public Q_SLOTS: void clear(); Q_SIGNALS: void updateRequested(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotSelectionChanged()) Q_PRIVATE_SLOT(d, void slotDoItClicked()) }; } } diff --git a/src/dialogs/setinitialpindialog.h b/src/dialogs/setinitialpindialog.h index cc32c7bae..7587e86f4 100644 --- a/src/dialogs/setinitialpindialog.h +++ b/src/dialogs/setinitialpindialog.h @@ -1,55 +1,55 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/setinitialpindialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace GpgME { class Error; } namespace Kleo { namespace Dialogs { class SetInitialPinDialog : public QDialog { Q_OBJECT public: explicit SetInitialPinDialog(QWidget *parent = nullptr); - ~SetInitialPinDialog(); + ~SetInitialPinDialog() override; void setNksPinPresent(bool); void setSigGPinPresent(bool); bool isComplete() const; public Q_SLOTS: void setNksPinSettingResult(const GpgME::Error &error); void setSigGPinSettingResult(const GpgME::Error &error); Q_SIGNALS: void nksPinRequested(); void sigGPinRequested(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotNksButtonClicked()) Q_PRIVATE_SLOT(d, void slotSigGButtonClicked()) }; } } diff --git a/src/dialogs/subkeyswidget.h b/src/dialogs/subkeyswidget.h index 283fce09d..afc27e0fc 100644 --- a/src/dialogs/subkeyswidget.h +++ b/src/dialogs/subkeyswidget.h @@ -1,45 +1,45 @@ /* SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace GpgME { class Key; } class SubKeysWidget : public QWidget { Q_OBJECT public: explicit SubKeysWidget(QWidget *parent = nullptr); - ~SubKeysWidget(); + ~SubKeysWidget() override; void setKey(const GpgME::Key &key); GpgME::Key key() const; private: class Private; const QScopedPointer d; }; class SubKeysDialog : public QDialog { Q_OBJECT public: explicit SubKeysDialog(QWidget *parent = nullptr); - ~SubKeysDialog(); + ~SubKeysDialog() override; void setKey(const GpgME::Key &key); GpgME::Key key() const; private: void readConfig(); void writeConfig(); }; diff --git a/src/dialogs/trustchainwidget.h b/src/dialogs/trustchainwidget.h index 06e4ea805..24e672ad4 100644 --- a/src/dialogs/trustchainwidget.h +++ b/src/dialogs/trustchainwidget.h @@ -1,43 +1,43 @@ /* SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace GpgME { class Key; } class TrustChainWidget : public QWidget { Q_OBJECT public: explicit TrustChainWidget(QWidget *parent = nullptr); - ~TrustChainWidget(); + ~TrustChainWidget() override; void setKey(const GpgME::Key &key); GpgME::Key key() const; private: class Private; const QScopedPointer d; }; class TrustChainDialog : public QDialog { Q_OBJECT public: explicit TrustChainDialog(QWidget *parent = nullptr); - ~TrustChainDialog(); + ~TrustChainDialog() override; void setKey(const GpgME::Key &key); GpgME::Key key() const; }; diff --git a/src/dialogs/weboftrustdialog.h b/src/dialogs/weboftrustdialog.h index 4841dcdca..0eb046ffa 100644 --- a/src/dialogs/weboftrustdialog.h +++ b/src/dialogs/weboftrustdialog.h @@ -1,33 +1,33 @@ /* SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include namespace GpgME { class Key; } namespace Kleo { class WebOfTrustWidget; class WebOfTrustDialog : public QDialog { Q_OBJECT public: explicit WebOfTrustDialog(QWidget *parent = nullptr); - ~WebOfTrustDialog(); + ~WebOfTrustDialog() override; void setKey(const GpgME::Key &key); GpgME::Key key() const; private: WebOfTrustWidget *mWidget; }; } // namespace Kleo diff --git a/src/kleopatraapplication.h b/src/kleopatraapplication.h index 1d0998620..e331eb9e8 100644 --- a/src/kleopatraapplication.h +++ b/src/kleopatraapplication.h @@ -1,104 +1,104 @@ /* kleopatraapplication.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include class MainWindow; class SysTrayIcon; class KleopatraApplication : public QApplication { Q_OBJECT public: /** Create a new Application object. You have to * make sure to call init afterwards to get a valid object. * This is to delay initialisation after the UniqueService * call is done and our init / call might be forwarded to * another instance. */ KleopatraApplication(int &argc, char *argv[]); - ~KleopatraApplication(); + ~KleopatraApplication() override; /** Initialize the application. Without calling init any * other call to KleopatraApplication will result in undefined behavior * and likely crash. */ void init(); static KleopatraApplication *instance() { return qobject_cast(qApp); } /** Starts a new instance or a command from the command line. * * Handles the parser options and starts the according commands. * If ignoreNewInstance is set this function does nothing. * The parser should have been initialized with kleopatra_options and * already processed. * If kleopatra is not session restored * * @param parser: The command line parser to use. * @param workingDirectory: Optional working directory for file arguments. * * @returns an empty QString on success. A localized error message otherwise. * */ QString newInstance(const QCommandLineParser &parser, const QString &workingDirectory = QString()); void setMainWindow(MainWindow *mw); const MainWindow *mainWindow() const; MainWindow *mainWindow(); const SysTrayIcon *sysTrayIcon() const; SysTrayIcon *sysTrayIcon(); void setIgnoreNewInstance(bool on); bool ignoreNewInstance() const; void toggleMainWindowVisibility(); void restoreMainWindow(); void openConfigDialogWithForeignParent(WId parentWId); public Q_SLOTS: void openOrRaiseMainWindow(); void openOrRaiseConfigDialog(); #ifndef QT_NO_SYSTEMTRAYICON void startMonitoringSmartCard(); void importCertificatesFromFile(const QStringList &files, GpgME::Protocol proto); #endif void encryptFiles(const QStringList &files, GpgME::Protocol proto); void signFiles(const QStringList &files, GpgME::Protocol proto); void signEncryptFiles(const QStringList &files, GpgME::Protocol proto); void decryptFiles(const QStringList &files, GpgME::Protocol proto); void verifyFiles(const QStringList &files, GpgME::Protocol proto); void decryptVerifyFiles(const QStringList &files, GpgME::Protocol proto); void checksumFiles(const QStringList &files, GpgME::Protocol /* unused */); void slotActivateRequested(const QStringList &arguments, const QString &workingDirectory); Q_SIGNALS: /* Emitted from slotActivateRequested to enable setting the * correct exitValue */ void setExitValue(int value); void configurationChanged(); private: class Private; kdtools::pimpl_ptr d; }; diff --git a/src/kwatchgnupg/kwatchgnupgconfig.h b/src/kwatchgnupg/kwatchgnupgconfig.h index ced586a2d..ed04f7a50 100644 --- a/src/kwatchgnupg/kwatchgnupgconfig.h +++ b/src/kwatchgnupg/kwatchgnupgconfig.h @@ -1,50 +1,50 @@ /* kwatchgnupgconfig.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2001, 2002, 2004, 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include class QCheckBox; class QComboBox; class KPluralHandlingSpinBox; class QDialogButtonBox; namespace Kleo { class FileNameRequester; } class KWatchGnuPGConfig : public QDialog { Q_OBJECT public: explicit KWatchGnuPGConfig(QWidget *parent = nullptr); - ~KWatchGnuPGConfig(); + ~KWatchGnuPGConfig() override; void loadConfig(); void saveConfig(); Q_SIGNALS: void reconfigure(); private Q_SLOTS: void slotChanged(); void slotSave(); void slotSetHistorySizeUnlimited(); private: Kleo::FileNameRequester *mExeED; Kleo::FileNameRequester *mSocketED; QComboBox *mLogLevelCB; KPluralHandlingSpinBox *mLoglenSB; QCheckBox *mWordWrapCB; QDialogButtonBox *mButtonBox; }; diff --git a/src/kwatchgnupg/kwatchgnupgmainwin.h b/src/kwatchgnupg/kwatchgnupgmainwin.h index 02712c193..93a4c0dcf 100644 --- a/src/kwatchgnupg/kwatchgnupgmainwin.h +++ b/src/kwatchgnupg/kwatchgnupgmainwin.h @@ -1,58 +1,58 @@ /* main.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2001, 2002, 2004 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class KWatchGnuPGTray; class KWatchGnuPGConfig; class KProcess; class QTextEdit; class KWatchGnuPGMainWindow : public KXmlGuiWindow { Q_OBJECT public: explicit KWatchGnuPGMainWindow(QWidget *parent = nullptr); - ~KWatchGnuPGMainWindow(); + ~KWatchGnuPGMainWindow() override; private Q_SLOTS: void slotWatcherExited(int, QProcess::ExitStatus); void slotReadStdout(); void slotSaveAs(); void slotQuit(); void slotClear(); void slotConfigure(); void slotConfigureToolbars(); void configureShortcuts(); void slotReadConfig(); public Q_SLOTS: /* reimp */ void show(); protected: bool queryClose() override; private: void createActions(); void startWatcher(); void setGnuPGConfig(); KProcess *mWatcher; QTextEdit *mCentralWidget; KWatchGnuPGTray *mSysTray; KWatchGnuPGConfig *mConfig; }; diff --git a/src/kwatchgnupg/tray.h b/src/kwatchgnupg/tray.h index 0139cdae1..fa57250de 100644 --- a/src/kwatchgnupg/tray.h +++ b/src/kwatchgnupg/tray.h @@ -1,31 +1,31 @@ /* main.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2001, 2002, 2004 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class KWatchGnuPGMainWindow; class KWatchGnuPGTray : public KStatusNotifierItem { Q_OBJECT public: explicit KWatchGnuPGTray(KWatchGnuPGMainWindow *mainwin); - virtual ~KWatchGnuPGTray(); + ~KWatchGnuPGTray() override; public Q_SLOTS: void setAttention(bool att); private: QIcon mNormalPix; QIcon mAttentionPix; }; diff --git a/src/libkleopatraclient/core/command.h b/src/libkleopatraclient/core/command.h index 4728e6b09..fad68fdc4 100644 --- a/src/libkleopatraclient/core/command.h +++ b/src/libkleopatraclient/core/command.h @@ -1,91 +1,91 @@ /* -*- mode: c++; c-basic-offset:4 -*- core/command.h This file is part of KleopatraClient, the Kleopatra interface library SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include "kleopatraclientcore_export.h" #include #include // only for WId, doesn't prevent linking against QtCore-only class QString; class QByteArray; class QVariant; namespace KleopatraClientCopy { class KLEOPATRACLIENTCORE_EXPORT Command : public QObject { Q_OBJECT public: explicit Command(QObject *parent = nullptr); - ~Command(); + ~Command() override; void setParentWId(WId wid); WId parentWId() const; void setServerLocation(const QString &location); QString serverLocation() const; bool waitForFinished(); bool waitForFinished(unsigned long ms); bool error() const; bool wasCanceled() const; QString errorString() const; qint64 serverPid() const; public Q_SLOTS: void start(); void cancel(); Q_SIGNALS: void started(); void finished(); protected: void setOptionValue(const char *name, const QVariant &value, bool critical = true); void setOption(const char *name, bool critical = true); void unsetOption(const char *name); QVariant optionValue(const char *name) const; bool isOptionSet(const char *name) const; bool isOptionCritical(const char *name) const; void setFilePaths(const QStringList &filePaths); QStringList filePaths() const; void setRecipients(const QStringList &recipients, bool informative); QStringList recipients() const; bool areRecipientsInformative() const; void setSenders(const QStringList &senders, bool informative); QStringList senders() const; bool areSendersInformative() const; void setInquireData(const char *what, const QByteArray &data); void unsetInquireData(const char *what); QByteArray inquireData(const char *what) const; bool isInquireDataSet(const char *what) const; QByteArray receivedData() const; void setCommand(const char *command); QByteArray command() const; protected: class Private; Private *d; Command(Private *p, QObject *parent); }; } diff --git a/src/libkleopatraclient/core/decryptverifyfilescommand.h b/src/libkleopatraclient/core/decryptverifyfilescommand.h index a6a68e430..23a0c129b 100644 --- a/src/libkleopatraclient/core/decryptverifyfilescommand.h +++ b/src/libkleopatraclient/core/decryptverifyfilescommand.h @@ -1,33 +1,33 @@ /* -*- mode: c++; c-basic-offset:4 -*- core/decryptverifyfilescommand.h This file is part of KleopatraClient, the Kleopatra interface library SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include namespace KleopatraClientCopy { class KLEOPATRACLIENTCORE_EXPORT DecryptVerifyFilesCommand : public Command { Q_OBJECT public: explicit DecryptVerifyFilesCommand(QObject *parent = nullptr); - ~DecryptVerifyFilesCommand(); + ~DecryptVerifyFilesCommand() override; // Inputs using Command::setFilePaths; using Command::filePaths; // No Outputs }; } diff --git a/src/libkleopatraclient/core/selectcertificatecommand.h b/src/libkleopatraclient/core/selectcertificatecommand.h index 22cd57b76..235527e6c 100644 --- a/src/libkleopatraclient/core/selectcertificatecommand.h +++ b/src/libkleopatraclient/core/selectcertificatecommand.h @@ -1,55 +1,55 @@ /* -*- mode: c++; c-basic-offset:4 -*- core/selectcertificatecommand.h This file is part of KleopatraClient, the Kleopatra interface library SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include namespace KleopatraClientCopy { class KLEOPATRACLIENTCORE_EXPORT SelectCertificateCommand : public Command { Q_OBJECT public: explicit SelectCertificateCommand(QObject *parent = nullptr); - ~SelectCertificateCommand(); + ~SelectCertificateCommand() override; // Inputs void setMultipleCertificatesAllowed(bool allow); bool multipleCertificatesAllowed() const; void setOnlySigningCertificatesAllowed(bool allow); bool onlySigningCertificatesAllowed() const; void setOnlyEncryptionCertificatesAllowed(bool allow); bool onlyEncryptionCertificatesAllowed() const; void setOnlyOpenPGPCertificatesAllowed(bool allow); bool onlyOpenPGPCertificatesAllowed() const; void setOnlyX509CertificatesAllowed(bool allow); bool onlyX509CertificatesAllowed() const; void setOnlySecretKeysAllowed(bool allow); bool onlySecretKeysAllowed() const; // Input/Outputs void setSelectedCertificates(const QStringList &certs); QStringList selectedCertificates() const; void setSelectedCertificate(const QString &cert); QString selectedCertificate() const; }; } diff --git a/src/libkleopatraclient/core/signencryptfilescommand.h b/src/libkleopatraclient/core/signencryptfilescommand.h index 735ab288e..a9abde031 100644 --- a/src/libkleopatraclient/core/signencryptfilescommand.h +++ b/src/libkleopatraclient/core/signencryptfilescommand.h @@ -1,33 +1,33 @@ /* -*- mode: c++; c-basic-offset:4 -*- core/signencryptfilescommand.h This file is part of KleopatraClient, the Kleopatra interface library SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include namespace KleopatraClientCopy { class KLEOPATRACLIENTCORE_EXPORT SignEncryptFilesCommand : public Command { Q_OBJECT public: explicit SignEncryptFilesCommand(QObject *parent = nullptr); - ~SignEncryptFilesCommand(); + ~SignEncryptFilesCommand() override; // Inputs using Command::setFilePaths; using Command::filePaths; // No Outputs }; } diff --git a/src/libkleopatraclient/gui/certificaterequester.h b/src/libkleopatraclient/gui/certificaterequester.h index e9dac28da..0806e1aa0 100644 --- a/src/libkleopatraclient/gui/certificaterequester.h +++ b/src/libkleopatraclient/gui/certificaterequester.h @@ -1,71 +1,71 @@ /* -*- mode: c++; c-basic-offset:4 -*- gui/certificaterequester.h This file is part of KleopatraClient, the Kleopatra interface library SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include "kleopatraclientgui_export.h" #include namespace KleopatraClientCopy { namespace Gui { class KLEOPATRACLIENTGUI_EXPORT CertificateRequester : public QWidget { Q_OBJECT Q_PROPERTY(bool multipleCertificatesAllowed READ multipleCertificatesAllowed WRITE setMultipleCertificatesAllowed) Q_PROPERTY(bool onlySigningCertificatesAllowed READ onlySigningCertificatesAllowed WRITE setOnlySigningCertificatesAllowed) Q_PROPERTY(bool onlyEncryptionCertificatesAllowed READ onlyEncryptionCertificatesAllowed WRITE setOnlyEncryptionCertificatesAllowed) Q_PROPERTY(bool onlyOpenPGPCertificatesAllowed READ onlyOpenPGPCertificatesAllowed WRITE setOnlyOpenPGPCertificatesAllowed) Q_PROPERTY(bool onlyX509CertificatesAllowed READ onlyX509CertificatesAllowed WRITE setOnlyX509CertificatesAllowed) Q_PROPERTY(bool onlySecretKeysAllowed READ onlySecretKeysAllowed WRITE setOnlySecretKeysAllowed) Q_PROPERTY(QStringList selectedCertificates READ selectedCertificates WRITE setSelectedCertificates) public: explicit CertificateRequester(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~CertificateRequester(); + ~CertificateRequester() override; void setMultipleCertificatesAllowed(bool allow); bool multipleCertificatesAllowed() const; void setOnlySigningCertificatesAllowed(bool allow); bool onlySigningCertificatesAllowed() const; void setOnlyEncryptionCertificatesAllowed(bool allow); bool onlyEncryptionCertificatesAllowed() const; void setOnlyOpenPGPCertificatesAllowed(bool allow); bool onlyOpenPGPCertificatesAllowed() const; void setOnlyX509CertificatesAllowed(bool allow); bool onlyX509CertificatesAllowed() const; void setOnlySecretKeysAllowed(bool allow); bool onlySecretKeysAllowed() const; void setSelectedCertificates(const QStringList &certs); QStringList selectedCertificates() const; void setSelectedCertificate(const QString &cert); QString selectedCertificate() const; Q_SIGNALS: void selectedCertificatesChanged(const QStringList &certs); private: class Private; Private *d; Q_PRIVATE_SLOT(d, void slotButtonClicked()) Q_PRIVATE_SLOT(d, void slotCommandFinished()) }; } } diff --git a/src/newcertificatewizard/listwidget.h b/src/newcertificatewizard/listwidget.h index db9f097c3..b405a0f9b 100644 --- a/src/newcertificatewizard/listwidget.h +++ b/src/newcertificatewizard/listwidget.h @@ -1,61 +1,61 @@ /* -*- mode: c++; c-basic-offset:4 -*- newcertificatewizard/listwidget.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 #include class QRegExp; class QString; #include namespace Kleo { namespace NewCertificateUi { class ListWidget : public QWidget { Q_OBJECT Q_PROPERTY(QStringList items READ items WRITE setItems USER true NOTIFY itemsChanged) Q_PROPERTY(QRegExp regExpFilter READ regExpFilter WRITE setRegExpFilter) Q_PROPERTY(QString defaultValue READ defaultValue WRITE setDefaultValue) public: explicit ListWidget(QWidget *parent = nullptr); - ~ListWidget(); + ~ListWidget() override; void setDefaultValue(const QString &defaultValue); QString defaultValue() const; void setRegExpFilter(const QRegExp &rx); QRegExp regExpFilter() const; QStringList items() const; public Q_SLOTS: void setItems(const QStringList &items); Q_SIGNALS: void itemsChanged(); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotAdd()) Q_PRIVATE_SLOT(d, void slotRemove()) Q_PRIVATE_SLOT(d, void slotUp()) Q_PRIVATE_SLOT(d, void slotDown()) Q_PRIVATE_SLOT(d, void slotSelectionChanged()) }; } } diff --git a/src/newcertificatewizard/newcertificatewizard.h b/src/newcertificatewizard/newcertificatewizard.h index 8bae513b2..b35e53e49 100644 --- a/src/newcertificatewizard/newcertificatewizard.h +++ b/src/newcertificatewizard/newcertificatewizard.h @@ -1,53 +1,53 @@ /* -*- mode: c++; c-basic-offset:4 -*- newcertificatewizard/newcertificatewizard.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 #include #include namespace Kleo { namespace NewCertificateUi { class WizardPage; } class NewCertificateWizard : public QWizard { Q_OBJECT public: explicit NewCertificateWizard(QWidget *parent = nullptr); - ~NewCertificateWizard(); + ~NewCertificateWizard() override; void setProtocol(GpgME::Protocol protocol); GpgME::Protocol protocol() const; enum Pages { ChooseProtocolPageId, EnterDetailsPageId, OverviewPageId, KeyCreationPageId, ResultPageId, NumPages }; private: class Private; kdtools::pimpl_ptr d; friend class ::Kleo::NewCertificateUi::WizardPage; }; } diff --git a/src/smartcard/deviceinfowatcher.h b/src/smartcard/deviceinfowatcher.h index 704645110..5fd99e272 100644 --- a/src/smartcard/deviceinfowatcher.h +++ b/src/smartcard/deviceinfowatcher.h @@ -1,39 +1,39 @@ /* smartcard/deviceinfowatcher.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include namespace Kleo { class DeviceInfoWatcher : public QObject { Q_OBJECT public: explicit DeviceInfoWatcher(QObject *parent = nullptr); - ~DeviceInfoWatcher(); + ~DeviceInfoWatcher() override; static bool isSupported(); void start(); Q_SIGNALS: void statusChanged(const QByteArray &details); private: class Worker; private: class Private; Private * const d; }; } diff --git a/src/smartcard/deviceinfowatcher_p.h b/src/smartcard/deviceinfowatcher_p.h index 83f32274c..24b09af1f 100644 --- a/src/smartcard/deviceinfowatcher_p.h +++ b/src/smartcard/deviceinfowatcher_p.h @@ -1,63 +1,63 @@ /* smartcard/deviceinfowatcher_p.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include namespace Kleo { class DeviceInfoWatcher::Worker : public QObject, public GpgME::StatusConsumer { Q_OBJECT public: - ~Worker(); + ~Worker() override; public Q_SLOTS: void start(); Q_SIGNALS: void statusChanged(const QByteArray &details); private: Q_INVOKABLE void poll(); void status(const char *status, const char *details) override; private: int mRetryDelay = 100; std::unique_ptr mContext; }; class DeviceInfoWatcher::Private { friend class ::Kleo::DeviceInfoWatcher; DeviceInfoWatcher *const q; public: explicit Private(DeviceInfoWatcher *qq); ~Private(); private: void start(); private: QThread workerThread; }; } diff --git a/src/smartcard/readerstatus.cpp b/src/smartcard/readerstatus.cpp index 8e8dea4d7..da9586bcb 100644 --- a/src/smartcard/readerstatus.cpp +++ b/src/smartcard/readerstatus.cpp @@ -1,1183 +1,1183 @@ /* -*- mode: c++; c-basic-offset:4 -*- smartcard/readerstatus.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #if GPGMEPP_VERSION >= 0x10E01 // 1.14.1 # define QGPGME_HAS_DEBUG # define GPGME_SUPPORTS_API_FOR_DEVICEINFOWATCHER #endif #include "readerstatus.h" #ifdef GPGME_SUPPORTS_API_FOR_DEVICEINFOWATCHER # include "deviceinfowatcher.h" #endif #include "keypairinfo.h" #include "utils/hex.h" #include #include #include #ifdef QGPGME_HAS_DEBUG # include #endif #include #include #include #include #include "openpgpcard.h" #include "netkeycard.h" #include "pivcard.h" #include "p15card.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "utils/kdtoolsglobal.h" #include "kleopatra_debug.h" using namespace Kleo; using namespace Kleo::SmartCard; using namespace GpgME; static ReaderStatus *self = nullptr; #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) static const char *flags[] = { "NOCARD", "PRESENT", "ACTIVE", "USABLE", }; static_assert(sizeof flags / sizeof * flags == Card::_NumScdStates, ""); static const char *prettyFlags[] = { "NoCard", "CardPresent", "CardActive", "CardUsable", "CardError", }; static_assert(sizeof prettyFlags / sizeof * prettyFlags == Card::NumStates, ""); Q_DECLARE_METATYPE(GpgME::Error) namespace { static bool gpgHasMultiCardMultiAppSupport() { return !(engineInfo(GpgME::GpgEngine).engineVersion() < "2.3.0"); } static QDebug operator<<(QDebug s, const std::string &string) { return s << QString::fromStdString(string); } #ifndef QGPGME_HAS_DEBUG static QDebug operator<<(QDebug s, const GpgME::Error &err) { const bool oldSetting = s.autoInsertSpaces(); s.nospace() << err.asString() << " (code: " << err.code() << ", source: " << err.source() << ")"; s.setAutoInsertSpaces(oldSetting); return s.maybeSpace(); } #endif static QDebug operator<<(QDebug s, const std::vector< std::pair > &v) { using pair = std::pair; s << '('; for (const pair &p : v) { s << "status(" << QString::fromStdString(p.first) << ") =" << QString::fromStdString(p.second) << '\n'; } return s << ')'; } struct CardApp { std::string serialNumber; std::string appName; }; static void logUnexpectedStatusLine(const std::pair &line, const std::string &prefix = std::string(), const std::string &command = std::string()) { qCWarning(KLEOPATRA_LOG) << (!prefix.empty() ? QString::fromStdString(prefix + ": ") : QString()) << "Unexpected status line" << (!command.empty() ? QString::fromStdString(" on " + command + ":") : QLatin1String(":")) << QString::fromStdString(line.first) << QString::fromStdString(line.second); } static int parse_app_version(const std::string &s) { return std::atoi(s.c_str()); } static Card::PinState parse_pin_state(const QString &s) { bool ok; int i = s.toInt(&ok); if (!ok) { qCDebug(KLEOPATRA_LOG) << "Failed to parse pin state" << s; return Card::UnknownPinState; } switch (i) { case -4: return Card::NullPin; case -3: return Card::PinBlocked; case -2: return Card::NoPin; case -1: return Card::UnknownPinState; default: if (i < 0) { return Card::UnknownPinState; } else { return Card::PinOk; } } } template static std::unique_ptr gpgagent_transact(std::shared_ptr &gpgAgent, const char *command, std::unique_ptr transaction, Error &err) { qCDebug(KLEOPATRA_LOG) << "gpgagent_transact(" << command << ")"; err = gpgAgent->assuanTransact(command, std::move(transaction)); static int cnt = 0; while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5) { // Esp. on Windows the agent processes may take their time so we try // in increasing waits for them to start up qCDebug(KLEOPATRA_LOG) << "Waiting for the daemons to start up"; cnt++; QThread::msleep(250 * cnt); err = gpgAgent->assuanTransact(command, gpgAgent->takeLastAssuanTransaction()); } if (err.code()) { qCDebug(KLEOPATRA_LOG) << "gpgagent_transact(" << command << "): Error:" << err; if (err.code() >= GPG_ERR_ASS_GENERAL && err.code() <= GPG_ERR_ASS_UNKNOWN_INQUIRE) { qCDebug(KLEOPATRA_LOG) << "Assuan problem, killing context"; gpgAgent.reset(); } return std::unique_ptr(); } std::unique_ptr t = gpgAgent->takeLastAssuanTransaction(); return std::unique_ptr(dynamic_cast(t.release())); } static std::unique_ptr gpgagent_default_transact(std::shared_ptr &gpgAgent, const char *command, Error &err) { return gpgagent_transact(gpgAgent, command, std::make_unique(), err); } static const std::string gpgagent_data(std::shared_ptr gpgAgent, const char *command, Error &err) { const std::unique_ptr t = gpgagent_default_transact(gpgAgent, command, err); if (t.get()) { qCDebug(KLEOPATRA_LOG) << "gpgagent_data(" << command << "): got" << QString::fromStdString(t->data()); return t->data(); } else { qCDebug(KLEOPATRA_LOG) << "gpgagent_data(" << command << "): t == NULL"; return std::string(); } } static const std::vector< std::pair > gpgagent_statuslines(std::shared_ptr gpgAgent, const char *what, Error &err) { const std::unique_ptr t = gpgagent_default_transact(gpgAgent, what, err); if (t.get()) { qCDebug(KLEOPATRA_LOG) << "agent_getattr_status(" << what << "): got" << t->statusLines(); return t->statusLines(); } else { qCDebug(KLEOPATRA_LOG) << "agent_getattr_status(" << what << "): t == NULL"; return std::vector >(); } } static const std::string gpgagent_status(const std::shared_ptr &gpgAgent, const char *what, Error &err) { const auto lines = gpgagent_statuslines (gpgAgent, what, err); // The status is only the last attribute // e.g. for SCD SERIALNO it would only be "SERIALNO" and for SCD GETATTR FOO // it would only be FOO const char *p = strrchr(what, ' '); const char *needle = (p + 1) ? (p + 1) : what; for (const auto &pair: lines) { if (pair.first == needle) { return pair.second; } } return std::string(); } static const std::string scd_getattr_status(std::shared_ptr &gpgAgent, const char *what, Error &err) { std::string cmd = "SCD GETATTR "; cmd += what; return gpgagent_status(gpgAgent, cmd.c_str(), err); } static const std::string getAttribute(std::shared_ptr &gpgAgent, const char *attribute, const char *versionHint) { Error err; const auto result = scd_getattr_status(gpgAgent, attribute, err); if (err) { if (err.code() == GPG_ERR_INV_NAME) { qCDebug(KLEOPATRA_LOG) << "Querying for attribute" << attribute << "not yet supported; needs GnuPG" << versionHint; } else { qCWarning(KLEOPATRA_LOG) << "Running SCD GETATTR " << attribute << " failed:" << err; } return std::string(); } return result; } static std::vector getCardsAndApps(std::shared_ptr &gpgAgent, Error &err) { std::vector result; if (gpgHasMultiCardMultiAppSupport()) { const std::string command = "SCD GETINFO all_active_apps"; const auto statusLines = gpgagent_statuslines(gpgAgent, command.c_str(), err); if (err) { return result; } for (const auto &statusLine: statusLines) { if (statusLine.first == "SERIALNO") { const auto serialNumberAndApps = QByteArray::fromStdString(statusLine.second).split(' '); if (serialNumberAndApps.size() >= 2) { const auto serialNumber = serialNumberAndApps[0]; auto apps = serialNumberAndApps.mid(1); // sort the apps to get a stable order independently of the currently selected application std::sort(apps.begin(), apps.end()); for (const auto &app: apps) { qCDebug(KLEOPATRA_LOG) << "getCardsAndApps(): Found card" << serialNumber << "with app" << app; result.push_back({ serialNumber.toStdString(), app.toStdString() }); } } else { logUnexpectedStatusLine(statusLine, "getCardsAndApps()", command); } } else { logUnexpectedStatusLine(statusLine, "getCardsAndApps()", command); } } } else { // use SCD SERIALNO to get the currently active card const auto serialNumber = gpgagent_status(gpgAgent, "SCD SERIALNO", err); if (err) { return result; } // use SCD GETATTR APPTYPE to find out which app is active auto appName = scd_getattr_status(gpgAgent, "APPTYPE", err); std::transform(appName.begin(), appName.end(), appName.begin(), [](unsigned char c){ return std::tolower(c); }); if (err) { return result; } result.push_back({ serialNumber, appName }); } return result; } static std::string switchCard(std::shared_ptr &gpgAgent, const std::string &serialNumber, Error &err) { const std::string command = "SCD SWITCHCARD " + serialNumber; const auto statusLines = gpgagent_statuslines(gpgAgent, command.c_str(), err); if (err) { return std::string(); } if (statusLines.size() == 1 && statusLines[0].first == "SERIALNO" && statusLines[0].second == serialNumber) { return serialNumber; } qCWarning(KLEOPATRA_LOG) << "switchCard():" << command << "returned" << statusLines << "(expected:" << "SERIALNO " + serialNumber << ")"; return std::string(); } static std::string switchApp(std::shared_ptr &gpgAgent, const std::string &serialNumber, const std::string &appName, Error &err) { const std::string command = "SCD SWITCHAPP " + appName; const auto statusLines = gpgagent_statuslines(gpgAgent, command.c_str(), err); if (err) { return std::string(); } if (statusLines.size() == 1 && statusLines[0].first == "SERIALNO" && statusLines[0].second.find(serialNumber + ' ' + appName) == 0) { return appName; } qCWarning(KLEOPATRA_LOG) << "switchApp():" << command << "returned" << statusLines << "(expected:" << "SERIALNO " + serialNumber + ' ' + appName + "..." << ")"; return std::string(); } static const char * get_openpgp_card_manufacturer_from_serial_number(const std::string &serialno) { qCDebug(KLEOPATRA_LOG) << "get_openpgp_card_manufacturer_from_serial_number(" << serialno.c_str() << ")"; const bool isProperOpenPGPCardSerialNumber = serialno.size() == 32 && serialno.substr(0, 12) == "D27600012401"; if (isProperOpenPGPCardSerialNumber) { const char *sn = serialno.c_str(); const int manufacturerId = xtoi_2(sn + 16)*256 + xtoi_2(sn + 18); switch (manufacturerId) { case 0x0001: return "PPC Card Systems"; case 0x0002: return "Prism"; case 0x0003: return "OpenFortress"; case 0x0004: return "Wewid"; case 0x0005: return "ZeitControl"; case 0x0006: return "Yubico"; case 0x0007: return "OpenKMS"; case 0x0008: return "LogoEmail"; case 0x002A: return "Magrathea"; case 0x1337: return "Warsaw Hackerspace"; case 0xF517: return "FSIJ"; /* 0x0000 and 0xFFFF are defined as test cards per spec, 0xFF00 to 0xFFFE are assigned for use with randomly created serial numbers. */ case 0x0000: case 0xffff: return "test card"; default: return (manufacturerId & 0xff00) == 0xff00 ? "unmanaged S/N range" : "unknown"; } } else { return "unknown"; } } static bool isOpenPGPCardSerialNumber(const std::string &serialNumber) { return serialNumber.size() == 32 && serialNumber.substr(0, 12) == "D27600012401"; } static const std::string getDisplaySerialNumber(std::shared_ptr &gpgAgent, Error &err) { const auto displaySerialNumber = scd_getattr_status(gpgAgent, "$DISPSERIALNO", err); if (err && err.code() != GPG_ERR_INV_NAME) { qCWarning(KLEOPATRA_LOG) << "Running SCD GETATTR $DISPSERIALNO failed:" << err; } return displaySerialNumber; } static void setDisplaySerialNumber(Card *card, std::shared_ptr &gpgAgent) { static const QRegularExpression leadingZeros(QStringLiteral("^0*")); Error err; const QString displaySerialNumber = QString::fromStdString(getDisplaySerialNumber(gpgAgent, err)); if (err) { card->setDisplaySerialNumber(QString::fromStdString(card->serialNumber())); return; } if (isOpenPGPCardSerialNumber(card->serialNumber()) && displaySerialNumber.size() == 12) { // add a space between manufacturer id and card id for OpenPGP cards card->setDisplaySerialNumber(displaySerialNumber.left(4) + QLatin1Char(' ') + displaySerialNumber.right(8)); } else { card->setDisplaySerialNumber(displaySerialNumber); } return; } static void handle_openpgp_card(std::shared_ptr &ci, std::shared_ptr &gpg_agent) { Error err; auto pgpCard = new OpenPGPCard(*ci); const auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --force", err); if (err.code()) { ci->setStatus(Card::CardError); return; } pgpCard->setCardInfo(info); if (pgpCard->manufacturer().empty()) { // fallback in case MANUFACTURER is not yet included in the card info pgpCard->setManufacturer(get_openpgp_card_manufacturer_from_serial_number(ci->serialNumber())); } setDisplaySerialNumber(pgpCard, gpg_agent); ci.reset(pgpCard); } static void readKeyPairInfoFromPIVCard(const std::string &keyRef, PIVCard *pivCard, const std::shared_ptr &gpg_agent) { Error err; const std::string command = std::string("SCD READKEY --info-only -- ") + keyRef; const auto keyPairInfoLines = gpgagent_statuslines(gpg_agent, command.c_str(), err); if (err) { qCWarning(KLEOPATRA_LOG) << "Running" << command << "failed:" << err; return; } for (const auto &pair: keyPairInfoLines) { if (pair.first == "KEYPAIRINFO") { const KeyPairInfo info = KeyPairInfo::fromStatusLine(pair.second); if (info.grip.empty()) { qCWarning(KLEOPATRA_LOG) << "Invalid KEYPAIRINFO status line" << QString::fromStdString(pair.second); continue; } pivCard->setKeyAlgorithm(keyRef, info.algorithm); } else { logUnexpectedStatusLine(pair, "readKeyPairInfoFromPIVCard()", command); } } } static void readCertificateFromPIVCard(const std::string &keyRef, PIVCard *pivCard, const std::shared_ptr &gpg_agent) { Error err; const std::string command = std::string("SCD READCERT ") + keyRef; const std::string certificateData = gpgagent_data(gpg_agent, command.c_str(), err); if (err && err.code() != GPG_ERR_NOT_FOUND) { qCWarning(KLEOPATRA_LOG) << "Running" << command << "failed:" << err; return; } if (certificateData.empty()) { qCDebug(KLEOPATRA_LOG) << "readCertificateFromPIVCard(" << QString::fromStdString(keyRef) << "): No certificate stored on card"; return; } qCDebug(KLEOPATRA_LOG) << "readCertificateFromPIVCard(" << QString::fromStdString(keyRef) << "): Found certificate stored on card"; pivCard->setCertificateData(keyRef, certificateData); } static void handle_piv_card(std::shared_ptr &ci, std::shared_ptr &gpg_agent) { Error err; auto pivCard = new PIVCard(*ci); const auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --force", err); if (err) { ci->setStatus(Card::CardError); return; } pivCard->setCardInfo(info); setDisplaySerialNumber(pivCard, gpg_agent); for (const KeyPairInfo &keyInfo : pivCard->keyInfos()) { if (!keyInfo.grip.empty()) { readKeyPairInfoFromPIVCard(keyInfo.keyRef, pivCard, gpg_agent); readCertificateFromPIVCard(keyInfo.keyRef, pivCard, gpg_agent); } } ci.reset(pivCard); } static void handle_p15_card(std::shared_ptr &ci, std::shared_ptr &gpg_agent) { Error err; auto p15Card = new P15Card(*ci); auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --force", err); if (err) { ci->setStatus(Card::CardError); return; } const auto fprs = gpgagent_statuslines(gpg_agent, "SCD GETATTR KEY-FPR", err); if (!err) { info.insert(info.end(), fprs.begin(), fprs.end()); } /* Create the key stubs */ gpgagent_statuslines(gpg_agent, "READKEY --card --no-data -- $SIGNKEYID", err); gpgagent_statuslines(gpg_agent, "READKEY --card --no-data -- $ENCRKEYID", err); p15Card->setCardInfo(info); setDisplaySerialNumber(p15Card, gpg_agent); ci.reset(p15Card); } static void handle_netkey_card(std::shared_ptr &ci, std::shared_ptr &gpg_agent) { Error err; auto nkCard = new NetKeyCard(*ci); ci.reset(nkCard); ci->setAppVersion(parse_app_version(scd_getattr_status(gpg_agent, "NKS-VERSION", err))); if (err.code()) { qCWarning(KLEOPATRA_LOG) << "Running SCD GETATTR NKS-VERSION failed:" << err; ci->setErrorMsg(QStringLiteral ("NKS-VERSION failed: ") + QString::fromUtf8(err.asString())); return; } if (ci->appVersion() != 3) { qCDebug(KLEOPATRA_LOG) << "not a NetKey v3 card, giving up. Version:" << ci->appVersion(); ci->setErrorMsg(QStringLiteral("NetKey v%1 cards are not supported.").arg(ci->appVersion())); return; } setDisplaySerialNumber(nkCard, gpg_agent); // the following only works for NKS v3... const auto chvStatus = QString::fromStdString( scd_getattr_status(gpg_agent, "CHV-STATUS", err)).split(QLatin1Char(' ')); if (err.code()) { qCDebug(KLEOPATRA_LOG) << "Running SCD GETATTR CHV-STATUS failed:" << err; ci->setErrorMsg(QStringLiteral ("CHV-Status failed: ") + QString::fromUtf8(err.asString())); return; } std::vector states; states.reserve(chvStatus.count()); // CHV Status for NKS v3 is // Pin1 (Normal pin) Pin2 (Normal PUK) // SigG1 SigG PUK. int num = 0; for (const auto &state: chvStatus) { const auto parsed = parse_pin_state (state); states.push_back(parsed); if (parsed == Card::NullPin) { if (num == 0) { ci->setHasNullPin(true); } } ++num; } nkCard->setPinStates(states); const auto info = gpgagent_statuslines(gpg_agent, "SCD LEARN --force", err); if (err) { ci->setStatus(Card::CardError); return; } nkCard->setCardInfo(info); } static std::shared_ptr get_card_status(const std::string &serialNumber, const std::string &appName, std::shared_ptr &gpg_agent) { qCDebug(KLEOPATRA_LOG) << "get_card_status(" << serialNumber << ',' << appName << ',' << gpg_agent.get() << ')'; auto ci = std::shared_ptr(new Card()); if (gpgHasMultiCardMultiAppSupport()) { // select card Error err; const auto result = switchCard(gpg_agent, serialNumber, err); if (err) { if (err.code() == GPG_ERR_CARD_NOT_PRESENT || err.code() == GPG_ERR_CARD_REMOVED) { ci->setStatus(Card::NoCard); } else { ci->setStatus(Card::CardError); } return ci; } if (result.empty()) { qCWarning(KLEOPATRA_LOG) << "get_card_status: switching card failed"; ci->setStatus(Card::CardError); return ci; } ci->setStatus(Card::CardPresent); } else { ci->setStatus(Card::CardPresent); } if (gpgHasMultiCardMultiAppSupport()) { // select app Error err; const auto result = switchApp(gpg_agent, serialNumber, appName, err); if (err) { if (err.code() == GPG_ERR_CARD_NOT_PRESENT || err.code() == GPG_ERR_CARD_REMOVED) { ci->setStatus(Card::NoCard); } else { ci->setStatus(Card::CardError); } return ci; } if (result.empty()) { qCWarning(KLEOPATRA_LOG) << "get_card_status: switching app failed"; ci->setStatus(Card::CardError); return ci; } } ci->setSerialNumber(serialNumber); ci->setSigningKeyRef(getAttribute(gpg_agent, "$SIGNKEYID", "2.2.18")); ci->setEncryptionKeyRef(getAttribute(gpg_agent, "$ENCRKEYID", "2.2.18")); // Handle different card types if (appName == NetKeyCard::AppName) { qCDebug(KLEOPATRA_LOG) << "get_card_status: found Netkey card" << ci->serialNumber().c_str() << "end"; handle_netkey_card(ci, gpg_agent); return ci; } else if (appName == OpenPGPCard::AppName) { qCDebug(KLEOPATRA_LOG) << "get_card_status: found OpenPGP card" << ci->serialNumber().c_str() << "end"; ci->setAuthenticationKeyRef(OpenPGPCard::pgpAuthKeyRef()); handle_openpgp_card(ci, gpg_agent); return ci; } else if (appName == PIVCard::AppName) { qCDebug(KLEOPATRA_LOG) << "get_card_status: found PIV card" << ci->serialNumber().c_str() << "end"; handle_piv_card(ci, gpg_agent); return ci; } else if (appName == P15Card::AppName) { qCDebug(KLEOPATRA_LOG) << "get_card_status: found P15 card" << ci->serialNumber().c_str() << "end"; handle_p15_card(ci, gpg_agent); return ci; } else { qCDebug(KLEOPATRA_LOG) << "get_card_status: unhandled application:" << appName; return ci; } return ci; } static bool isCardNotPresentError(const GpgME::Error &err) { // see fixup_scd_errors() in gpg-card.c return err && ((err.code() == GPG_ERR_CARD_NOT_PRESENT) || ((err.code() == GPG_ERR_ENODEV || err.code() == GPG_ERR_CARD_REMOVED) && (err.sourceID() == GPG_ERR_SOURCE_SCD))); } static std::vector > update_cardinfo(std::shared_ptr &gpgAgent) { qCDebug(KLEOPATRA_LOG) << "update_cardinfo()"; // ensure that a card is present and that all cards are properly set up { Error err; const char *command = (gpgHasMultiCardMultiAppSupport()) ? "SCD SERIALNO --all" : "SCD SERIALNO"; const std::string serialno = gpgagent_status(gpgAgent, command, err); if (err) { if (isCardNotPresentError(err)) { qCDebug(KLEOPATRA_LOG) << "update_cardinfo: No card present"; return std::vector >(); } else { qCWarning(KLEOPATRA_LOG) << "Running" << command << "failed:" << err; auto ci = std::shared_ptr(new Card()); ci->setStatus(Card::CardError); return std::vector >(1, ci); } } } Error err; const std::vector cardApps = getCardsAndApps(gpgAgent, err); if (err) { if (isCardNotPresentError(err)) { qCDebug(KLEOPATRA_LOG) << "update_cardinfo: No card present"; return std::vector >(); } else { qCWarning(KLEOPATRA_LOG) << "Getting active apps on all inserted cards failed:" << err; auto ci = std::shared_ptr(new Card()); ci->setStatus(Card::CardError); return std::vector >(1, ci); } } std::vector > cards; for (const auto &cardApp: cardApps) { const auto card = get_card_status(cardApp.serialNumber, cardApp.appName, gpgAgent); cards.push_back(card); } return cards; } } // namespace struct Transaction { CardApp cardApp; QByteArray command; QPointer receiver; const char *slot; AssuanTransaction* assuanTransaction; }; static const Transaction updateTransaction = { { "__all__", "__all__" }, "__update__", nullptr, nullptr, nullptr }; static const Transaction quitTransaction = { { "__all__", "__all__" }, "__quit__", nullptr, nullptr, nullptr }; namespace { class ReaderStatusThread : public QThread { Q_OBJECT public: explicit ReaderStatusThread(QObject *parent = nullptr) : QThread(parent), m_gnupgHomePath(Kleo::gnupgHomeDirectory()), m_transactions(1, updateTransaction) // force initial scan { connect(this, &ReaderStatusThread::oneTransactionFinished, this, &ReaderStatusThread::slotOneTransactionFinished); } std::vector > cardInfos() const { const QMutexLocker locker(&m_mutex); return m_cardInfos; } Card::Status cardStatus(unsigned int slot) const { const QMutexLocker locker(&m_mutex); if (slot < m_cardInfos.size()) { return m_cardInfos[slot]->status(); } else { return Card::NoCard; } } void addTransaction(const Transaction &t) { const QMutexLocker locker(&m_mutex); m_transactions.push_back(t); m_waitForTransactions.wakeOne(); } Q_SIGNALS: void firstCardWithNullPinChanged(const std::string &serialNumber); void anyCardCanLearnKeysChanged(bool); void cardAdded(const std::string &serialNumber, const std::string &appName); void cardChanged(const std::string &serialNumber, const std::string &appName); void cardRemoved(const std::string &serialNumber, const std::string &appName); void oneTransactionFinished(const GpgME::Error &err); public Q_SLOTS: void deviceStatusChanged(const QByteArray &details) { qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread[GUI]::deviceStatusChanged(" << details << ")"; addTransaction(updateTransaction); } void ping() { qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread[GUI]::ping()"; addTransaction(updateTransaction); } void stop() { const QMutexLocker locker(&m_mutex); m_transactions.push_front(quitTransaction); m_waitForTransactions.wakeOne(); } private Q_SLOTS: void slotOneTransactionFinished(const GpgME::Error &err) { std::list ft; KDAB_SYNCHRONIZED(m_mutex) ft.splice(ft.begin(), m_finishedTransactions); for (const Transaction &t : std::as_const(ft)) if (t.receiver && t.slot && *t.slot) { QMetaObject::invokeMethod(t.receiver, t.slot, Qt::DirectConnection, Q_ARG(GpgME::Error, err)); } } private: void run() override { while (true) { std::shared_ptr gpgAgent; CardApp cardApp; QByteArray command; bool nullSlot = false; AssuanTransaction* assuanTransaction = nullptr; std::list item; std::vector > oldCards; Error err; std::unique_ptr c = Context::createForEngine(AssuanEngine, &err); if (err.code() == GPG_ERR_NOT_SUPPORTED) { return; } gpgAgent = std::shared_ptr(c.release()); KDAB_SYNCHRONIZED(m_mutex) { while (m_transactions.empty()) { // go to sleep waiting for more work: qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread[2nd]: waiting for commands"; m_waitForTransactions.wait(&m_mutex); } // splice off the first transaction without // copying, so we own it without really importing // it into this thread (the QPointer isn't // thread-safe): item.splice(item.end(), m_transactions, m_transactions.begin()); // make local copies of the interesting stuff so // we can release the mutex again: cardApp = item.front().cardApp; command = item.front().command; nullSlot = !item.front().slot; // we take ownership of the assuan transaction std::swap(assuanTransaction, item.front().assuanTransaction); oldCards = m_cardInfos; } qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread[2nd]: new iteration command=" << command << " ; nullSlot=" << nullSlot; // now, let's see what we got: if (nullSlot && command == quitTransaction.command) { return; // quit } if ((nullSlot && command == updateTransaction.command)) { std::vector > newCards = update_cardinfo(gpgAgent); KDAB_SYNCHRONIZED(m_mutex) m_cardInfos = newCards; bool anyLC = false; std::string firstCardWithNullPin; bool anyError = false; for (const auto &newCard: newCards) { const auto serialNumber = newCard->serialNumber(); const auto appName = newCard->appName(); const auto matchingOldCard = std::find_if(oldCards.cbegin(), oldCards.cend(), [serialNumber, appName] (const std::shared_ptr &card) { return card->serialNumber() == serialNumber && card->appName() == appName; }); if (matchingOldCard == oldCards.cend()) { qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << serialNumber << "with app" << appName << "was added"; Q_EMIT cardAdded(serialNumber, appName); } else { if (*newCard != **matchingOldCard) { qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << serialNumber << "with app" << appName << "changed"; Q_EMIT cardChanged(serialNumber, appName); } oldCards.erase(matchingOldCard); } if (newCard->canLearnKeys()) { anyLC = true; } if (newCard->hasNullPin() && firstCardWithNullPin.empty()) { firstCardWithNullPin = newCard->serialNumber(); } if (newCard->status() == Card::CardError) { anyError = true; } } for (const auto &oldCard: oldCards) { qCDebug(KLEOPATRA_LOG) << "ReaderStatusThread: Card" << oldCard->serialNumber() << "with app" << oldCard->appName() << "was removed"; Q_EMIT cardRemoved(oldCard->serialNumber(), oldCard->appName()); } Q_EMIT firstCardWithNullPinChanged(firstCardWithNullPin); Q_EMIT anyCardCanLearnKeysChanged(anyLC); if (anyError) { gpgAgent.reset(); } } else { GpgME::Error err; if (gpgHasMultiCardMultiAppSupport()) { switchCard(gpgAgent, cardApp.serialNumber, err); if (!err) { switchApp(gpgAgent, cardApp.serialNumber, cardApp.appName, err); } } if (!err) { if (assuanTransaction) { (void)gpgagent_transact(gpgAgent, command.constData(), std::unique_ptr(assuanTransaction), err); } else { (void)gpgagent_default_transact(gpgAgent, command.constData(), err); } } KDAB_SYNCHRONIZED(m_mutex) // splice 'item' into m_finishedTransactions: m_finishedTransactions.splice(m_finishedTransactions.end(), item); Q_EMIT oneTransactionFinished(err); } } } private: mutable QMutex m_mutex; QWaitCondition m_waitForTransactions; const QString m_gnupgHomePath; // protected by m_mutex: std::vector > m_cardInfos; std::list m_transactions, m_finishedTransactions; }; } class ReaderStatus::Private : ReaderStatusThread { friend class Kleo::SmartCard::ReaderStatus; ReaderStatus *const q; public: explicit Private(ReaderStatus *qq) : ReaderStatusThread(qq), q(qq), watcher() { KDAB_SET_OBJECT_NAME(watcher); qRegisterMetaType("Kleo::SmartCard::Card::Status"); qRegisterMetaType("GpgME::Error"); connect(this, &::ReaderStatusThread::cardAdded, q, &ReaderStatus::cardAdded); connect(this, &::ReaderStatusThread::cardChanged, q, &ReaderStatus::cardChanged); connect(this, &::ReaderStatusThread::cardRemoved, q, &ReaderStatus::cardRemoved); connect(this, &::ReaderStatusThread::firstCardWithNullPinChanged, q, &ReaderStatus::firstCardWithNullPinChanged); connect(this, &::ReaderStatusThread::anyCardCanLearnKeysChanged, q, &ReaderStatus::anyCardCanLearnKeysChanged); #ifdef GPGME_SUPPORTS_API_FOR_DEVICEINFOWATCHER if (DeviceInfoWatcher::isSupported()) { qCDebug(KLEOPATRA_LOG) << "ReaderStatus::Private: Using new DeviceInfoWatcher"; connect(&devInfoWatcher, &DeviceInfoWatcher::statusChanged, this, &::ReaderStatusThread::deviceStatusChanged); } else #endif { qCDebug(KLEOPATRA_LOG) << "ReaderStatus::Private: Using deprecated FileSystemWatcher"; watcher.whitelistFiles(QStringList(QStringLiteral("reader_*.status"))); watcher.addPath(Kleo::gnupgHomeDirectory()); watcher.setDelay(100); connect(&watcher, &FileSystemWatcher::triggered, this, &::ReaderStatusThread::ping); } } - ~Private() + ~Private() override { stop(); if (!wait(100)) { terminate(); wait(); } } private: std::string firstCardWithNullPinImpl() const { const auto cis = cardInfos(); const auto firstWithNullPin = std::find_if(cis.cbegin(), cis.cend(), [](const std::shared_ptr &ci) { return ci->hasNullPin(); }); return firstWithNullPin != cis.cend() ? (*firstWithNullPin)->serialNumber() : std::string(); } bool anyCardCanLearnKeysImpl() const { const auto cis = cardInfos(); return std::any_of(cis.cbegin(), cis.cend(), [](const std::shared_ptr &ci) { return ci->canLearnKeys(); }); } private: FileSystemWatcher watcher; #ifdef GPGME_SUPPORTS_API_FOR_DEVICEINFOWATCHER DeviceInfoWatcher devInfoWatcher; #endif }; ReaderStatus::ReaderStatus(QObject *parent) : QObject(parent), d(new Private(this)) { self = this; qRegisterMetaType("std::string"); } ReaderStatus::~ReaderStatus() { self = nullptr; } // slot void ReaderStatus::startMonitoring() { d->start(); #ifdef GPGME_SUPPORTS_API_FOR_DEVICEINFOWATCHER if (DeviceInfoWatcher::isSupported()) { d->devInfoWatcher.start(); } #endif } // static ReaderStatus *ReaderStatus::mutableInstance() { return self; } // static const ReaderStatus *ReaderStatus::instance() { return self; } Card::Status ReaderStatus::cardStatus(unsigned int slot) const { return d->cardStatus(slot); } std::string ReaderStatus::firstCardWithNullPin() const { return d->firstCardWithNullPinImpl(); } bool ReaderStatus::anyCardCanLearnKeys() const { return d->anyCardCanLearnKeysImpl(); } void ReaderStatus::startSimpleTransaction(const std::shared_ptr &card, const QByteArray &command, QObject *receiver, const char *slot) { const CardApp cardApp = { card->serialNumber(), card->appName() }; const Transaction t = { cardApp, command, receiver, slot, nullptr }; d->addTransaction(t); } void ReaderStatus::startTransaction(const std::shared_ptr &card, const QByteArray &command, QObject *receiver, const char *slot, std::unique_ptr transaction) { const CardApp cardApp = { card->serialNumber(), card->appName() }; const Transaction t = { cardApp, command, receiver, slot, transaction.release() }; d->addTransaction(t); } void ReaderStatus::updateStatus() { d->ping(); } std::vector > ReaderStatus::getCards() const { return d->cardInfos(); } std::shared_ptr ReaderStatus::getCard(const std::string &serialNumber, const std::string &appName) const { for (const auto &card: d->cardInfos()) { if (card->serialNumber() == serialNumber && card->appName() == appName) { qCDebug(KLEOPATRA_LOG) << "ReaderStatus::getCard() - Found card with serial number" << serialNumber << "and app" << appName; return card; } } qCWarning(KLEOPATRA_LOG) << "ReaderStatus::getCard() - Did not find card with serial number" << serialNumber << "and app" << appName; return std::shared_ptr(); } // static std::string ReaderStatus::switchCard(std::shared_ptr& ctx, const std::string& serialNumber, Error& err) { return ::switchCard(ctx, serialNumber, err); } // static std::string ReaderStatus::switchApp(std::shared_ptr& ctx, const std::string& serialNumber, const std::string& appName, Error& err) { return ::switchApp(ctx, serialNumber, appName, err); } // static Error ReaderStatus::switchCardAndApp(const std::string &serialNumber, const std::string &appName) { Error err; if (!(engineInfo(GpgEngine).engineVersion() < "2.3.0")) { std::unique_ptr c = Context::createForEngine(AssuanEngine, &err); if (err.code() == GPG_ERR_NOT_SUPPORTED) { return err; } auto assuanContext = std::shared_ptr(c.release()); const auto resultSerialNumber = switchCard(assuanContext, serialNumber, err); if (err || resultSerialNumber != serialNumber) { qCWarning(KLEOPATRA_LOG) << "Switching to card" << QString::fromStdString(serialNumber) << "failed"; if (!err) { err = Error::fromCode(GPG_ERR_UNEXPECTED); } return err; } const auto resultAppName = switchApp(assuanContext, serialNumber, appName, err); if (err || resultAppName != appName) { qCWarning(KLEOPATRA_LOG) << "Switching card to" << QString::fromStdString(appName) << "app failed"; if (!err) { err = Error::fromCode(GPG_ERR_UNEXPECTED); } return err; } } return err; } namespace { static auto split(const std::string &s, char c) { std::vector result; auto start = 0; auto end = s.find(c, start); while (end != s.npos) { result.push_back(s.substr(start, end - start)); start = end + 1; end = s.find(c, start); } result.push_back(s.substr(start)); return result; } } // static std::vector ReaderStatus::getReaders(Error &err) { std::vector result; auto c = Context::createForEngine(AssuanEngine, &err); if (err) { qCDebug(KLEOPATRA_LOG) << "Creating context for Assuan engine failed:" << err; return result; } auto assuanContext = std::shared_ptr(c.release()); const std::string command = "SCD GETINFO reader_list"; const auto readersData = gpgagent_data(assuanContext, command.c_str(), err); if (err) { return result; } const auto readers = hexdecode(readersData); result = split(readers, '\n'); return result; } #include "readerstatus.moc" diff --git a/src/uiserver/assuancommand.h b/src/uiserver/assuancommand.h index 52c907f19..445ad4e9a 100644 --- a/src/uiserver/assuancommand.h +++ b/src/uiserver/assuancommand.h @@ -1,385 +1,385 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/assuancommand.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 #ifdef HAVE_ASSUAN2 #include #endif #include #include // for WId #include #include #include #include class QVariant; class QObject; #include struct assuan_context_s; namespace Kleo { class Input; class Output; class AssuanCommandFactory; /*! \brief Base class for GnuPG UI Server commands \note large parts of this are outdated by now!

Implementing a new AssuanCommand

You do not directly inherit AssuanCommand, unless you want to deal with implementing low-level, repetitive things like name() in terms of staticName(). Assuming you don't, then you inherit your command class from AssuanCommandMixin, passing your class as the template argument to AssuanCommandMixin, like this: \code class MyFooCommand : public AssuanCommandMixin { \endcode (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) You then choose a command name, and return that from the static method staticName(), which is by convention queried by both AssuanCommandMixin<> and GenericAssuanCommandFactory<>: \code static const char * staticName() { return "MYFOO"; } \endcode The string should be all-uppercase by convention, but the UiServer implementation doesn't enforce this. The next step is to implement start(), the starting point of command execution:

Executing the command

\code int start( const std::string & line ) { \endcode This should set everything up and check the parameters in \a line and any options this command understands. If there's an error, choose one of the gpg-error codes and create a gpg_error_t from it using the protected makeError() function: \code return makeError( GPG_ERR_NOT_IMPLEMENTED ); \endcode But usually, you will want to create a dialog, or call some GpgME function from here. In case of errors from GpgME, you shouldn't pipe them through makeError(), but return them as-is. This will preserve the error source. Error created using makeError() will have Kleopatra as their error source, so watch out what you're doing :) In addition to options and the command line, your command might require bulk data input or output. That's what the bulk input and output channels are for. You can check whether the client handed you an input channel by checking that bulkInputDevice() isn't NULL, likewise for bulkOutputDevice(). If everything is ok, you return 0. This indicates to the client that the command has been accepted and is now in progress. In this mode (start() returned 0), there are a bunch of options for your command to do. Some commands may require additional information from the client. The options passed to start() are designed to be persistent across commands, and rather limited in length (there's a strict line length limit in the assuan protocol with no line continuation mechanism). The same is true for command line arguments, which, in addition, you have to parse yourself. Those usually apply only to this command, and not to following ones. If you need data that might be larger than the line length limit, you can either expect it on the bulkInputDevice(), or, if you have the need for more than one such data channel, or the data is optional or conditional on some condition that can only be determined during command execution, you can \em inquire the missing information from the client. As an example, a VERIFY command would expect the signed data on the bulkInputDevice(). But if the input stream doesn't contain an embedded (opaque) signature, indicating a \em detached signature, it would go and inquire that data from the client. Here's how it works: \code const int err = inquire( "DETACHED_SIGNATURE", this, SLOT(slotDetachedSignature(int,QByteArray,QByteArray)) ); if ( err ) done( err ); \endcode This should be self-explanatory: You give a slot to call when the data has arrived. The slot's first argument is an error code. The second the data (if any), and the third is just repeating what you gave as inquire()'s first argument. As usual, you can leave argument off of the end, if you are not interested in them. You can do as many inquiries as you want, but only one at a time. You should periodically send status updates to the client. You do that by calling sendStatus(). Once your command has finished executing, call done(). If it's with an error code, call done(err) like above. Do not forget to call done() when done!. It will close bulkInputDevice(), bulkOutputDevice(), and send an OK or ERR message back to the client. At that point, your command has finished executing, and a new one can be accepted, or the connection closed. Apropos connection closed. The only way for the client to cancel an operation is to shut down the connection. In this case, the canceled() function will be called. At that point, the connection to the client will have been broken already, and all you can do is pack your things and go down gracefully. If _you_ detect that the user has canceled (your dialog contains a cancel button, doesn't it?), then you should instead call done( GPG_ERR_CANCELED ), like for normal operation.

Registering the command with UiServer

To register a command, you implement a AssuanCommandFactory for your AssuanCommand subclass, and register it with the UiServer. This can be made considerably easier using GenericAssuanCommandFactory: \code UiServer server; server.registerCommandFactory( shared_ptr( new GenericAssuanCommandFactory ) ); // more registerCommandFactory calls... server.start(); \endcode */ class AssuanCommand : public ExecutionContext, public std::enable_shared_from_this { // defined in assuanserverconnection.cpp! public: AssuanCommand(); - virtual ~AssuanCommand(); + ~AssuanCommand() override; int start(); void canceled(); virtual const char *name() const = 0; class Memento { public: virtual ~Memento() {} }; template class TypedMemento : public Memento { T m_t; public: explicit TypedMemento(const T &t) : m_t(t) {} const T &get() const { return m_t; } T &get() { return m_t; } }; template static std::shared_ptr< TypedMemento > make_typed_memento(const T &t) { return std::shared_ptr< TypedMemento >(new TypedMemento(t)); } static int makeError(int code); // convenience methods: enum Mode { NoMode, EMail, FileManager }; Mode checkMode() const; enum CheckProtocolOption { AllowProtocolMissing = 0x01 }; GpgME::Protocol checkProtocol(Mode mode, int options = 0) const; void applyWindowID(QWidget *w) const override { doApplyWindowID(w); } WId parentWId() const; void setNohup(bool on); bool isNohup() const; bool isDone() const; QString sessionTitle() const; unsigned int sessionId() const; bool informativeRecipients() const; bool informativeSenders() const; const std::vector &recipients() const; const std::vector &senders() const; bool hasMemento(const QByteArray &tag) const; std::shared_ptr memento(const QByteArray &tag) const; template std::shared_ptr mementoAs(const QByteArray &tag) const { return std::dynamic_pointer_cast(this->memento(tag)); } QByteArray registerMemento(const std::shared_ptr &mem); QByteArray registerMemento(const QByteArray &tag, const std::shared_ptr &mem); void removeMemento(const QByteArray &tag); template T mementoContent(const QByteArray &tag) const { if (std::shared_ptr< TypedMemento > m = mementoAs< TypedMemento >(tag)) { return m->get(); } else { return T(); } } bool hasOption(const char *opt) const; QVariant option(const char *opt) const; const std::map &options() const; const std::vector< std::shared_ptr > &inputs() const; const std::vector< std::shared_ptr > &messages() const; const std::vector< std::shared_ptr > &outputs() const; QStringList fileNames() const; unsigned int numFiles() const; void sendStatus(const char *keyword, const QString &text); void sendStatusEncoded(const char *keyword, const std::string &text); void sendData(const QByteArray &data, bool moreToCome = false); int inquire(const char *keyword, QObject *receiver, const char *slot, unsigned int maxSize = 0); void done(const GpgME::Error &err = GpgME::Error()); void done(const GpgME::Error &err, const QString &details); void done(int err) { done(GpgME::Error(err)); } void done(int err, const QString &details) { done(GpgME::Error(err), details); } private: virtual void doCanceled() = 0; virtual int doStart() = 0; private: void doApplyWindowID(QWidget *w) const; private: const std::map< QByteArray, std::shared_ptr > &mementos() const; private: friend class ::Kleo::AssuanCommandFactory; class Private; kdtools::pimpl_ptr d; }; class AssuanCommandFactory { public: virtual ~AssuanCommandFactory() {} virtual std::shared_ptr create() const = 0; virtual const char *name() const = 0; #ifndef HAVE_ASSUAN2 typedef int(*_Handler)(assuan_context_s *, char *); #else using _Handler = gpg_error_t (*)(assuan_context_s *, char *); #endif virtual _Handler _handler() const = 0; #ifndef HAVE_ASSUAN2 static int _handle(assuan_context_s *, char *, const char *); #else static gpg_error_t _handle(assuan_context_s *, char *, const char *); #endif }; template class GenericAssuanCommandFactory : public AssuanCommandFactory { AssuanCommandFactory::_Handler _handler() const override { return &GenericAssuanCommandFactory::_handle; } #ifndef HAVE_ASSUAN2 static int _handle(assuan_context_s *_ctx, char *_line) { #else static gpg_error_t _handle(assuan_context_s *_ctx, char *_line) { #endif return AssuanCommandFactory::_handle(_ctx, _line, Command::staticName()); } std::shared_ptr create() const override { return make(); } const char *name() const override { return Command::staticName(); } public: static std::shared_ptr make() { return std::shared_ptr(new Command); } }; template class AssuanCommandMixin : public Base { protected: /* reimp */ const char *name() const override { return Derived::staticName(); } }; } diff --git a/src/uiserver/assuanserverconnection.cpp b/src/uiserver/assuanserverconnection.cpp index bdc1af038..7900d87b4 100644 --- a/src/uiserver/assuanserverconnection.cpp +++ b/src/uiserver/assuanserverconnection.cpp @@ -1,1690 +1,1690 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/assuanserverconnection.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 */ #ifndef QT_NO_CAST_TO_ASCII # define QT_NO_CAST_TO_ASCII #endif #ifndef QT_NO_CAST_FROM_ASCII # define QT_NO_CAST_FROM_ASCII #endif #include #include #include "assuanserverconnection.h" #include "assuancommand.h" #include "sessiondata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __GLIBCXX__ # include // for is_sorted #endif #ifdef Q_OS_WIN32 # include # include #else # include # include #endif using namespace Kleo; static const unsigned int INIT_SOCKET_FLAGS = 3; // says info assuan... //static int(*USE_DEFAULT_HANDLER)(assuan_context_t,char*) = 0; static const int FOR_READING = 0; static const unsigned int MAX_ACTIVE_FDS = 32; #ifdef HAVE_ASSUAN2 static void my_assuan_release(assuan_context_t ctx) { if (ctx) { assuan_release(ctx); } } #endif // std::shared_ptr for assuan_context_t w/ deleter enforced to assuan_deinit_server: using AssuanContextBase = std::shared_ptr::type>; struct AssuanContext : AssuanContextBase { AssuanContext() : AssuanContextBase() {} #ifndef HAVE_ASSUAN2 explicit AssuanContext(assuan_context_t ctx) : AssuanContextBase(ctx, &assuan_deinit_server) {} #else explicit AssuanContext(assuan_context_t ctx) : AssuanContextBase(ctx, &my_assuan_release) {} #endif #ifndef HAVE_ASSUAN2 void reset(assuan_context_t ctx = 0) { AssuanContextBase::reset(ctx, &assuan_deinit_server); } #else void reset(assuan_context_t ctx = nullptr) { AssuanContextBase::reset(ctx, &my_assuan_release); } #endif }; static inline gpg_error_t assuan_process_done_msg(assuan_context_t ctx, gpg_error_t err, const char *err_msg) { return assuan_process_done(ctx, assuan_set_error(ctx, err, err_msg)); } static inline gpg_error_t assuan_process_done_msg(assuan_context_t ctx, gpg_error_t err, const std::string &err_msg) { return assuan_process_done_msg(ctx, err, err_msg.c_str()); } static inline gpg_error_t assuan_process_done_msg(assuan_context_t ctx, gpg_error_t err, const QString &err_msg) { return assuan_process_done_msg(ctx, err, err_msg.toUtf8().constData()); } static std::map upcase_option(const char *option, std::map options) { std::string value; bool value_found = false; auto it = options.begin(); while (it != options.end()) if (qstricmp(it->first.c_str(), option) == 0) { value = it->second; options.erase(it++); value_found = true; } else { ++it; } if (value_found) { options[option] = value; } return options; } static std::map parse_commandline(const char *line) { std::map result; if (line) { const char *begin = line; const char *lastEQ = nullptr; while (*line) { if (*line == ' ' || *line == '\t') { if (begin != line) { if (begin[0] == '-' && begin[1] == '-') { begin += 2; // skip initial "--" } if (lastEQ && lastEQ > begin) { result[ std::string(begin, lastEQ - begin) ] = hexdecode(std::string(lastEQ + 1, line - (lastEQ + 1))); } else { result[ std::string(begin, line - begin) ] = std::string(); } } begin = line + 1; } else if (*line == '=') { if (line == begin) throw Exception(gpg_error(GPG_ERR_ASS_SYNTAX), i18n("No option name given")); else { lastEQ = line; } } ++line; } if (begin != line) { if (begin[0] == '-' && begin[1] == '-') { begin += 2; // skip initial "--" } if (lastEQ && lastEQ > begin) { result[ std::string(begin, lastEQ - begin) ] = hexdecode(std::string(lastEQ + 1, line - (lastEQ + 1))); } else { result[ begin ] = std::string(); } } } return result; } static WId wid_from_string(const QString &winIdStr, bool *ok = nullptr) { return static_cast(winIdStr.toULongLong(ok, 16)); } static void apply_window_id(QWidget *widget, const QString &winIdStr) { if (!widget || winIdStr.isEmpty()) { return; } bool ok = false; const WId wid = wid_from_string(winIdStr, &ok); if (!ok) { qCDebug(KLEOPATRA_LOG) << "window-id value" << wid << "doesn't look like a number"; return; } if (QWidget *pw = QWidget::find(wid)) { widget->setParent(pw, widget->windowFlags()); } else { widget->setAttribute(Qt::WA_NativeWindow, true); KWindowSystem::setMainWindow(widget->windowHandle(), wid); } } // // // AssuanServerConnection: // // class AssuanServerConnection::Private : public QObject { Q_OBJECT friend class ::Kleo::AssuanServerConnection; friend class ::Kleo::AssuanCommandFactory; friend class ::Kleo::AssuanCommand; AssuanServerConnection *const q; public: Private(assuan_fd_t fd_, const std::vector< std::shared_ptr > &factories_, AssuanServerConnection *qq); - ~Private(); + ~Private() override; Q_SIGNALS: void startKeyManager(); public Q_SLOTS: void slotReadActivity(int) { Q_ASSERT(ctx); #ifndef HAVE_ASSUAN2 if (const int err = assuan_process_next(ctx.get())) { #else int done = false; if (const int err = assuan_process_next(ctx.get(), &done) || done) { #endif //if ( err == -1 || gpg_err_code(err) == GPG_ERR_EOF ) { topHalfDeletion(); if (nohupedCommands.empty()) { bottomHalfDeletion(); } //} else { //assuan_process_done( ctx.get(), err ); //return; //} } } int startCommandBottomHalf(); private: void nohupDone(AssuanCommand *cmd) { const auto it = std::find_if(nohupedCommands.begin(), nohupedCommands.end(), [cmd](const std::shared_ptr &other) { return other.get() == cmd; }); Q_ASSERT(it != nohupedCommands.end()); nohupedCommands.erase(it); if (nohupedCommands.empty() && closed) { bottomHalfDeletion(); } } void commandDone(AssuanCommand *cmd) { if (!cmd || cmd != currentCommand.get()) { return; } currentCommand.reset(); } void topHalfDeletion() { if (currentCommand) { currentCommand->canceled(); } if (fd != ASSUAN_INVALID_FD) { #if defined(Q_OS_WIN32) CloseHandle(fd); #else ::close(fd); #endif } notifiers.clear(); closed = true; } void bottomHalfDeletion() { if (sessionId) { SessionDataHandler::instance()->exitSession(sessionId); } cleanup(); const QPointer that = this; Q_EMIT q->closed(q); if (that) { // still there q->deleteLater(); } } private: #ifndef HAVE_ASSUAN2 static void reset_handler(assuan_context_t ctx_) { #else static gpg_error_t reset_handler(assuan_context_t ctx_, char *) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); conn.reset(); #ifdef HAVE_ASSUAN2 return 0; #endif } #ifndef HAVE_ASSUAN2 static int option_handler(assuan_context_t ctx_, const char *key, const char *value) { #else static gpg_error_t option_handler(assuan_context_t ctx_, const char *key, const char *value) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); if (key && key[0] == '-' && key[1] == '-') { key += 2; // skip "--" } conn.options[key] = QString::fromUtf8(value); return 0; //return gpg_error( GPG_ERR_UNKNOWN_OPTION ); } #ifndef HAVE_ASSUAN2 static int session_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t session_handler(assuan_context_t ctx_, char *line) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); const QString str = QString::fromUtf8(line); QRegExp rx(QLatin1String("(\\d+)(?:\\s+(.*))?")); if (!rx.exactMatch(str)) { static const QString errorString = i18n("Parse error"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_SYNTAX), errorString); } bool ok = false; if (const qulonglong id = rx.cap(1).toULongLong(&ok)) { if (ok && id <= std::numeric_limits::max()) { SessionDataHandler::instance()->enterSession(id); conn.sessionId = id; } else { static const QString errorString = i18n("Parse error: numeric session id too large"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_SYNTAX), errorString); } } if (!rx.cap(2).isEmpty()) { conn.sessionTitle = rx.cap(2); } qCDebug(KLEOPATRA_LOG) << "session_handler: " << "id=" << static_cast(conn.sessionId) << ", title=" << qPrintable(conn.sessionTitle); return assuan_process_done(ctx_, 0); } #ifndef HAVE_ASSUAN2 static int capabilities_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t capabilities_handler(assuan_context_t ctx_, char *line) { #endif if (!QByteArray(line).trimmed().isEmpty()) { static const QString errorString = i18n("CAPABILITIES does not take arguments"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_PARAMETER), errorString); } static const char capabilities[] = "SENDER=info\n" "RECIPIENT=info\n" "SESSION\n" ; return assuan_process_done(ctx_, assuan_send_data(ctx_, capabilities, sizeof capabilities - 1)); } #ifndef HAVE_ASSUAN2 static int getinfo_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t getinfo_handler(assuan_context_t ctx_, char *line) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); if (qstrcmp(line, "version") == 0) { static const char version[] = "Kleopatra " KLEOPATRA_VERSION_STRING; return assuan_process_done(ctx_, assuan_send_data(ctx_, version, sizeof version - 1)); } QByteArray ba; if (qstrcmp(line, "pid") == 0) { ba = QByteArray::number(QCoreApplication::applicationPid()); } else if (qstrcmp(line, "options") == 0) { ba = conn.dumpOptions(); } else if (qstrcmp(line, "x-mementos") == 0) { ba = conn.dumpMementos(); } else if (qstrcmp(line, "senders") == 0) { ba = conn.dumpSenders(); } else if (qstrcmp(line, "recipients") == 0) { ba = conn.dumpRecipients(); } else if (qstrcmp(line, "x-files") == 0) { ba = conn.dumpFiles(); } else { static const QString errorString = i18n("Unknown value for WHAT"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_PARAMETER), errorString); } return assuan_process_done(ctx_, assuan_send_data(ctx_, ba.constData(), ba.size())); } #ifndef HAVE_ASSUAN2 static int start_keymanager_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t start_keymanager_handler(assuan_context_t ctx_, char *line) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); if (line && *line) { static const QString errorString = i18n("START_KEYMANAGER does not take arguments"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_PARAMETER), errorString); } Q_EMIT conn.q->startKeyManagerRequested(); return assuan_process_done(ctx_, 0); } #ifndef HAVE_ASSUAN2 static int start_confdialog_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t start_confdialog_handler(assuan_context_t ctx_, char *line) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); if (line && *line) { static const QString errorString = i18n("START_CONFDIALOG does not take arguments"); return assuan_process_done_msg(ctx_, gpg_error(GPG_ERR_ASS_PARAMETER), errorString); } Q_EMIT conn.q->startConfigDialogRequested(); return assuan_process_done(ctx_, 0); } template struct Input_or_Output : std::conditional {}; // format: TAG (FD|FD=\d+|FILE=...) template #ifndef HAVE_ASSUAN2 static int IO_handler(assuan_context_t ctx_, char *line_, T_memptr which) { #else static gpg_error_t IO_handler(assuan_context_t ctx_, char *line_, T_memptr which) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); char *binOpt = strstr(line_, "--binary"); if (binOpt && !in) { /* Note there is also --armor and --base64 allowed but we don't need * to parse those because they are default. * We remove it here so that it is not parsed as an Option.*/ memset(binOpt, ' ', 8); } try { /*const*/ std::map options = upcase_option("FD", upcase_option("FILE", parse_commandline(line_))); if (options.size() < 1 || options.size() > 2) { throw gpg_error(GPG_ERR_ASS_SYNTAX); } std::shared_ptr< typename Input_or_Output::type > io; if (options.count("FD")) { if (options.count("FILE")) { throw gpg_error(GPG_ERR_CONFLICT); } assuan_fd_t fd = ASSUAN_INVALID_FD; const std::string fdstr = options["FD"]; if (fdstr.empty()) { if (const gpg_error_t err = assuan_receivefd(conn.ctx.get(), &fd)) { throw err; } } else { #if defined(Q_OS_WIN32) fd = (assuan_fd_t)std::stoi(fdstr); #else fd = std::stoi(fdstr); #endif } io = Input_or_Output::type::createFromPipeDevice(fd, in ? i18n("Message #%1", (conn.*which).size() + 1) : QString()); options.erase("FD"); } else if (options.count("FILE")) { if (options.count("FD")) { throw gpg_error(GPG_ERR_CONFLICT); } const QString filePath = QFile::decodeName(options["FILE"].c_str()); if (filePath.isEmpty()) { throw Exception(gpg_error(GPG_ERR_ASS_SYNTAX), i18n("Empty file path")); } const QFileInfo fi(filePath); if (!fi.isAbsolute()) { throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Only absolute file paths are allowed")); } if (!fi.isFile()) { throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Only files are allowed in INPUT/OUTPUT FILE")); } else { io = Input_or_Output::type::createFromFile(fi.absoluteFilePath(), true); } options.erase("FILE"); } else { throw gpg_error(GPG_ERR_ASS_PARAMETER); } if (options.size()) { throw gpg_error(GPG_ERR_UNKNOWN_OPTION); } (conn.*which).push_back(io); if (binOpt && !in) { auto out = reinterpret_cast (io.get()); out->setBinaryOpt(true); qCDebug(KLEOPATRA_LOG) << "Configured output for binary data"; } qCDebug(KLEOPATRA_LOG) << "AssuanServerConnection: added" << io->label(); return assuan_process_done(conn.ctx.get(), 0); } catch (const GpgME::Exception &e) { return assuan_process_done_msg(conn.ctx.get(), e.error().encodedError(), e.message().c_str()); } catch (const std::exception &) { return assuan_process_done(conn.ctx.get(), gpg_error(GPG_ERR_ASS_SYNTAX)); } catch (const gpg_error_t &e) { return assuan_process_done(conn.ctx.get(), e); } catch (...) { return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), "unknown exception caught"); } } #ifndef HAVE_ASSUAN2 static int input_handler(assuan_context_t ctx, char *line) { #else static gpg_error_t input_handler(assuan_context_t ctx, char *line) { #endif return IO_handler(ctx, line, &Private::inputs); } #ifndef HAVE_ASSUAN2 static int output_handler(assuan_context_t ctx, char *line) { #else static gpg_error_t output_handler(assuan_context_t ctx, char *line) { #endif return IO_handler(ctx, line, &Private::outputs); } #ifndef HAVE_ASSUAN2 static int message_handler(assuan_context_t ctx, char *line) { #else static gpg_error_t message_handler(assuan_context_t ctx, char *line) { #endif return IO_handler(ctx, line, &Private::messages); } #ifndef HAVE_ASSUAN2 static int file_handler(assuan_context_t ctx_, char *line) { #else static gpg_error_t file_handler(assuan_context_t ctx_, char *line) { #endif Q_ASSERT(assuan_get_pointer(ctx_)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx_)); try { const QFileInfo fi(QFile::decodeName(hexdecode(line).c_str())); if (!fi.isAbsolute()) { throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Only absolute file paths are allowed")); } if (!fi.exists()) { throw gpg_error(GPG_ERR_ENOENT); } if (!fi.isReadable() || (fi.isDir() && !fi.isExecutable())) { throw gpg_error(GPG_ERR_EPERM); } conn.files.push_back(fi.absoluteFilePath()); return assuan_process_done(conn.ctx.get(), 0); } catch (const Exception &e) { return assuan_process_done_msg(conn.ctx.get(), e.error().encodedError(), e.message().toUtf8().constData()); } catch (const gpg_error_t &e) { return assuan_process_done(conn.ctx.get(), e); } catch (...) { return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), i18n("unknown exception caught").toUtf8().constData()); } } static bool parse_informative(const char *&begin, GpgME::Protocol &protocol) { protocol = GpgME::UnknownProtocol; bool informative = false; const char *pos = begin; while (true) { while (*pos == ' ' || *pos == '\t') { ++pos; } if (qstrnicmp(pos, "--info", strlen("--info")) == 0) { informative = true; pos += strlen("--info"); if (*pos == '=') { ++pos; break; } } else if (qstrnicmp(pos, "--protocol=", strlen("--protocol=")) == 0) { pos += strlen("--protocol="); if (qstrnicmp(pos, "OpenPGP", strlen("OpenPGP")) == 0) { protocol = GpgME::OpenPGP; pos += strlen("OpenPGP"); } else if (qstrnicmp(pos, "CMS", strlen("CMS")) == 0) { protocol = GpgME::CMS; pos += strlen("CMS"); } else { ; } } else if (qstrncmp(pos, "-- ", strlen("-- ")) == 0) { pos += 3; while (*pos == ' ' || *pos == '\t') { ++pos; } break; } else { break; } } begin = pos; return informative; } template #ifndef HAVE_ASSUAN2 static int recipient_sender_handler(T_memptr mp, T_memptr2 info, assuan_context_t ctx, char *line, bool sender = false) { #else static gpg_error_t recipient_sender_handler(T_memptr mp, T_memptr2 info, assuan_context_t ctx, char *line, bool sender = false) { #endif Q_ASSERT(assuan_get_pointer(ctx)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx)); if (!line || !*line) { return assuan_process_done(conn.ctx.get(), gpg_error(GPG_ERR_INV_ARG)); } const char *begin = line; const char *const end = begin + qstrlen(line); GpgME::Protocol proto = GpgME::UnknownProtocol; const bool informative = parse_informative(begin, proto); if (!(conn.*mp).empty() && informative != (conn.*info)) return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_CONFLICT), i18n("Cannot mix --info with non-info SENDER or RECIPIENT").toUtf8().constData()); KMime::Types::Mailbox mb; if (!KMime::HeaderParsing::parseMailbox(begin, end, mb)) return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_INV_ARG), i18n("Argument is not a valid RFC-2822 mailbox").toUtf8().constData()); if (begin != end) return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_INV_ARG), i18n("Garbage after valid RFC-2822 mailbox detected").toUtf8().constData()); (conn.*info) = informative; (conn.*mp).push_back(mb); const QString email = mb.addrSpec().asString(); (void)assuan_write_line(conn.ctx.get(), qPrintable(QString::asprintf("# ok, parsed as \"%s\"", qPrintable(email)))); if (sender && !informative) { return AssuanCommandFactory::_handle(conn.ctx.get(), line, "PREP_SIGN"); } else { return assuan_process_done(ctx, 0); } } #ifndef HAVE_ASSUAN2 static int recipient_handler(assuan_context_t ctx, char *line) { #else static gpg_error_t recipient_handler(assuan_context_t ctx, char *line) { #endif return recipient_sender_handler(&Private::recipients, &Private::informativeRecipients, ctx, line); } #ifndef HAVE_ASSUAN2 static int sender_handler(assuan_context_t ctx, char *line) { #else static gpg_error_t sender_handler(assuan_context_t ctx, char *line) { #endif return recipient_sender_handler(&Private::senders, &Private::informativeSenders, ctx, line, true); } QByteArray dumpOptions() const { QByteArray result; for (auto it = options.begin(), end = options.end(); it != end; ++it) { result += it->first.c_str() + it->second.toString().toUtf8() + '\n'; } return result; } static QByteArray dumpStringList(const QStringList &sl) { return sl.join(QLatin1Char('\n')).toUtf8(); } template static QByteArray dumpStringList(const T_container &c) { QStringList sl; std::copy(c.begin(), c.end(), std::back_inserter(sl)); return dumpStringList(sl); } template static QByteArray dumpMailboxes(const T_container &c) { QStringList sl; std::transform(c.begin(), c.end(), std::back_inserter(sl), [](typename T_container::const_reference val) { return val.prettyAddress(); }); return dumpStringList(sl); } QByteArray dumpSenders() const { return dumpMailboxes(senders); } QByteArray dumpRecipients() const { return dumpMailboxes(recipients); } QByteArray dumpMementos() const { QByteArray result; for (auto it = mementos.begin(), end = mementos.end(); it != end; ++it) { char buf[2 + 2 * sizeof(void *) + 2]; sprintf(buf, "0x%p\n", (void *)it->second.get()); buf[sizeof(buf) - 1] = '\0'; result += it->first + QByteArray::fromRawData(buf, sizeof buf); } return result; } QByteArray dumpFiles() const { QStringList rv; rv.reserve(files.size()); std::copy(files.cbegin(), files.cend(), std::back_inserter(rv)); return dumpStringList(rv); } void cleanup(); void reset() { options.clear(); senders.clear(); informativeSenders = false; recipients.clear(); informativeRecipients = false; sessionTitle.clear(); sessionId = 0; mementos.clear(); files.clear(); std::for_each(inputs.begin(), inputs.end(), std::mem_fn(&Input::finalize)); inputs.clear(); std::for_each(outputs.begin(), outputs.end(), std::mem_fn(&Output::finalize)); outputs.clear(); std::for_each(messages.begin(), messages.end(), std::mem_fn(&Input::finalize)); messages.clear(); bias = GpgME::UnknownProtocol; } assuan_fd_t fd; AssuanContext ctx; bool closed : 1; bool cryptoCommandsEnabled : 1; bool commandWaitingForCryptoCommandsEnabled : 1; bool currentCommandIsNohup : 1; bool informativeSenders; // address taken, so no : 1 bool informativeRecipients; // address taken, so no : 1 GpgME::Protocol bias; QString sessionTitle; unsigned int sessionId; std::vector< std::shared_ptr > notifiers; std::vector< std::shared_ptr > factories; // sorted: _detail::ByName std::shared_ptr currentCommand; std::vector< std::shared_ptr > nohupedCommands; std::map options; std::vector senders, recipients; std::vector< std::shared_ptr > inputs, messages; std::vector< std::shared_ptr > outputs; std::vector files; std::map< QByteArray, std::shared_ptr > mementos; }; void AssuanServerConnection::Private::cleanup() { Q_ASSERT(nohupedCommands.empty()); reset(); currentCommand.reset(); currentCommandIsNohup = false; commandWaitingForCryptoCommandsEnabled = false; notifiers.clear(); ctx.reset(); fd = ASSUAN_INVALID_FD; } AssuanServerConnection::Private::Private(assuan_fd_t fd_, const std::vector< std::shared_ptr > &factories_, AssuanServerConnection *qq) : QObject(), q(qq), fd(fd_), closed(false), cryptoCommandsEnabled(false), commandWaitingForCryptoCommandsEnabled(false), currentCommandIsNohup(false), informativeSenders(false), informativeRecipients(false), bias(GpgME::UnknownProtocol), sessionId(0), factories(factories_) { #ifdef __GLIBCXX__ Q_ASSERT(__gnu_cxx::is_sorted(factories_.begin(), factories_.end(), _detail::ByName())); #endif if (fd == ASSUAN_INVALID_FD) { throw Exception(gpg_error(GPG_ERR_INV_ARG), "pre-assuan_init_socket_server_ext"); } #ifndef HAVE_ASSUAN2 assuan_context_t naked_ctx = 0; if (const gpg_error_t err = assuan_init_socket_server_ext(&naked_ctx, fd, INIT_SOCKET_FLAGS)) #else { assuan_context_t naked_ctx = nullptr; if (const gpg_error_t err = assuan_new(&naked_ctx)) { throw Exception(err, "assuan_new"); } ctx.reset(naked_ctx); } if (const gpg_error_t err = assuan_init_socket_server(ctx.get(), fd, INIT_SOCKET_FLAGS)) #endif throw Exception(err, "assuan_init_socket_server_ext"); #ifndef HAVE_ASSUAN2 ctx.reset(naked_ctx); naked_ctx = 0; #endif // for callbacks, associate the context with this connection: assuan_set_pointer(ctx.get(), this); FILE *const logFile = Log::instance()->logFile(); assuan_set_log_stream(ctx.get(), logFile ? logFile : stderr); // register FDs with the event loop: assuan_fd_t fds[MAX_ACTIVE_FDS]; const int numFDs = assuan_get_active_fds(ctx.get(), FOR_READING, fds, MAX_ACTIVE_FDS); Q_ASSERT(numFDs != -1); // == 1 if (!numFDs || fds[0] != fd) { const std::shared_ptr sn(new QSocketNotifier((intptr_t)fd, QSocketNotifier::Read), std::mem_fn(&QObject::deleteLater)); connect(sn.get(), &QSocketNotifier::activated, this, &Private::slotReadActivity); notifiers.push_back(sn); } notifiers.reserve(notifiers.size() + numFDs); for (int i = 0; i < numFDs; ++i) { const std::shared_ptr sn(new QSocketNotifier((intptr_t)fds[i], QSocketNotifier::Read), std::mem_fn(&QObject::deleteLater)); connect(sn.get(), &QSocketNotifier::activated, this, &Private::slotReadActivity); notifiers.push_back(sn); } // register our INPUT/OUTPUT/MESSGAE/FILE handlers: #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "INPUT", input_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "INPUT", input_handler, "")) #endif throw Exception(err, "register \"INPUT\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "MESSAGE", message_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "MESSAGE", message_handler, "")) #endif throw Exception(err, "register \"MESSAGE\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "OUTPUT", output_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "OUTPUT", output_handler, "")) #endif throw Exception(err, "register \"OUTPUT\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "FILE", file_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "FILE", file_handler, "")) #endif throw Exception(err, "register \"FILE\" handler"); // register user-defined commands: for (std::shared_ptr fac : std::as_const(factories)) #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), fac->name(), fac->_handler())) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), fac->name(), fac->_handler(), "")) #endif throw Exception(err, std::string("register \"") + fac->name() + "\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "GETINFO", getinfo_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "GETINFO", getinfo_handler, "")) #endif throw Exception(err, "register \"GETINFO\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "START_KEYMANAGER", start_keymanager_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "START_KEYMANAGER", start_keymanager_handler, "")) #endif throw Exception(err, "register \"START_KEYMANAGER\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "START_CONFDIALOG", start_confdialog_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "START_CONFDIALOG", start_confdialog_handler, "")) #endif throw Exception(err, "register \"START_CONFDIALOG\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "RECIPIENT", recipient_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "RECIPIENT", recipient_handler, "")) #endif throw Exception(err, "register \"RECIPIENT\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "SENDER", sender_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "SENDER", sender_handler, "")) #endif throw Exception(err, "register \"SENDER\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "SESSION", session_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "SESSION", session_handler, "")) #endif throw Exception(err, "register \"SESSION\" handler"); #ifndef HAVE_ASSUAN2 if (const gpg_error_t err = assuan_register_command(ctx.get(), "CAPABILITIES", capabilities_handler)) #else if (const gpg_error_t err = assuan_register_command(ctx.get(), "CAPABILITIES", capabilities_handler, "")) #endif throw Exception(err, "register \"CAPABILITIES\" handler"); assuan_set_hello_line(ctx.get(), "GPG UI server (Kleopatra/" KLEOPATRA_VERSION_STRING ") ready to serve"); //assuan_set_hello_line( ctx.get(), GPG UI server (qApp->applicationName() + " v" + kapp->applicationVersion() + "ready to serve" ) // some notifiers we're interested in: if (const gpg_error_t err = assuan_register_reset_notify(ctx.get(), reset_handler)) { throw Exception(err, "register reset notify"); } if (const gpg_error_t err = assuan_register_option_handler(ctx.get(), option_handler)) { throw Exception(err, "register option handler"); } // and last, we need to call assuan_accept, which doesn't block // (d/t INIT_SOCKET_FLAGS), but performs vital connection // establishing handling: if (const gpg_error_t err = assuan_accept(ctx.get())) { throw Exception(err, "assuan_accept"); } } AssuanServerConnection::Private::~Private() { cleanup(); } AssuanServerConnection::AssuanServerConnection(assuan_fd_t fd, const std::vector< std::shared_ptr > &factories, QObject *p) : QObject(p), d(new Private(fd, factories, this)) { } AssuanServerConnection::~AssuanServerConnection() {} void AssuanServerConnection::enableCryptoCommands(bool on) { if (on == d->cryptoCommandsEnabled) { return; } d->cryptoCommandsEnabled = on; if (d->commandWaitingForCryptoCommandsEnabled) { QTimer::singleShot(0, d.get(), &Private::startCommandBottomHalf); } } // // // AssuanCommand: // // namespace Kleo { class InquiryHandler : public QObject { Q_OBJECT public: #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) explicit InquiryHandler(const char *keyword_, QObject *p = nullptr) : QObject(p), # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) buffer(0), buflen(0), # endif keyword(keyword_) { } # if defined(HAVE_ASSUAN2) || defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) # ifndef HAVE_ASSUAN2 static int handler(void *cb_data, int rc, unsigned char *buffer, size_t buflen) # else static gpg_error_t handler(void *cb_data, gpg_error_t rc, unsigned char *buffer, size_t buflen) # endif { Q_ASSERT(cb_data); auto this_ = static_cast(cb_data); Q_EMIT this_->signal(rc, QByteArray::fromRawData(reinterpret_cast(buffer), buflen), this_->keyword); std::free(buffer); delete this_; return 0; } # else static int handler(void *cb_data, int rc) { Q_ASSERT(cb_data); InquiryHandler *this_ = static_cast(cb_data); Q_EMIT this_->signal(rc, QByteArray::fromRawData(reinterpret_cast(this_->buffer), this_->buflen), this_->keyword); std::free(this_->buffer); delete this_; return 0; } # endif private: #if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) friend class ::Kleo::AssuanCommand; unsigned char *buffer; size_t buflen; #endif const char *keyword; #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) Q_SIGNALS: void signal(int rc, const QByteArray &data, const QByteArray &keyword); }; } // namespace Kleo class AssuanCommand::Private { public: Private() : informativeRecipients(false), informativeSenders(false), bias(GpgME::UnknownProtocol), done(false), nohup(false) { } std::map options; std::vector< std::shared_ptr > inputs, messages; std::vector< std::shared_ptr > outputs; std::vector files; std::vector recipients, senders; bool informativeRecipients, informativeSenders; GpgME::Protocol bias; QString sessionTitle; unsigned int sessionId; QByteArray utf8ErrorKeepAlive; AssuanContext ctx; bool done; bool nohup; }; AssuanCommand::AssuanCommand() : d(new Private) { } AssuanCommand::~AssuanCommand() { } int AssuanCommand::start() { try { if (const int err = doStart()) if (!d->done) { done(err); } return 0; } catch (const Exception &e) { if (!d->done) { done(e.error_code(), e.message()); } return 0; } catch (const GpgME::Exception &e) { if (!d->done) { done(e.error(), QString::fromLocal8Bit(e.message().c_str())); } return 0; } catch (const std::exception &e) { if (!d->done) { done(makeError(GPG_ERR_INTERNAL), i18n("Caught unexpected exception: %1", QString::fromLocal8Bit(e.what()))); } return 0; } catch (...) { if (!d->done) { done(makeError(GPG_ERR_INTERNAL), i18n("Caught unknown exception - please report this error to the developers.")); } return 0; } } void AssuanCommand::canceled() { d->done = true; doCanceled(); } // static int AssuanCommand::makeError(int code) { return makeGnuPGError(code); } bool AssuanCommand::hasOption(const char *opt) const { return d->options.count(opt); } QVariant AssuanCommand::option(const char *opt) const { const auto it = d->options.find(opt); if (it == d->options.end()) { return QVariant(); } else { return it->second; } } const std::map &AssuanCommand::options() const { return d->options; } namespace { template std::vector keys(const std::map &map) { std::vector result; result.resize(map.size()); for (typename std::map::const_iterator it = map.begin(), end = map.end(); it != end; ++it) { result.push_back(it->first); } return result; } } const std::map< QByteArray, std::shared_ptr > &AssuanCommand::mementos() const { // oh, hack :( Q_ASSERT(assuan_get_pointer(d->ctx.get())); const AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(d->ctx.get())); return conn.mementos; } bool AssuanCommand::hasMemento(const QByteArray &tag) const { if (const unsigned int id = sessionId()) { return SessionDataHandler::instance()->sessionData(id)->mementos.count(tag) || mementos().count(tag); } else { return mementos().count(tag); } } std::shared_ptr AssuanCommand::memento(const QByteArray &tag) const { if (const unsigned int id = sessionId()) { const std::shared_ptr sdh = SessionDataHandler::instance(); const std::shared_ptr sd = sdh->sessionData(id); const auto it = sd->mementos.find(tag); if (it != sd->mementos.end()) { return it->second; } } const auto it = mementos().find(tag); if (it == mementos().end()) { return std::shared_ptr(); } else { return it->second; } } QByteArray AssuanCommand::registerMemento(const std::shared_ptr &mem) { const QByteArray tag = QByteArray::number(reinterpret_cast(mem.get()), 36); return registerMemento(tag, mem); } QByteArray AssuanCommand::registerMemento(const QByteArray &tag, const std::shared_ptr &mem) { // oh, hack :( Q_ASSERT(assuan_get_pointer(d->ctx.get())); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(d->ctx.get())); if (const unsigned int id = sessionId()) { SessionDataHandler::instance()->sessionData(id)->mementos[tag] = mem; } else { conn.mementos[tag] = mem; } return tag; } void AssuanCommand::removeMemento(const QByteArray &tag) { // oh, hack :( Q_ASSERT(assuan_get_pointer(d->ctx.get())); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(d->ctx.get())); conn.mementos.erase(tag); if (const unsigned int id = sessionId()) { SessionDataHandler::instance()->sessionData(id)->mementos.erase(tag); } } const std::vector< std::shared_ptr > &AssuanCommand::inputs() const { return d->inputs; } const std::vector< std::shared_ptr > &AssuanCommand::messages() const { return d->messages; } const std::vector< std::shared_ptr > &AssuanCommand::outputs() const { return d->outputs; } QStringList AssuanCommand::fileNames() const { QStringList rv; rv.reserve(d->files.size()); std::copy(d->files.cbegin(), d->files.cend(), std::back_inserter(rv)); return rv; } unsigned int AssuanCommand::numFiles() const { return d->files.size(); } void AssuanCommand::sendStatus(const char *keyword, const QString &text) { sendStatusEncoded(keyword, text.toUtf8().constData()); } void AssuanCommand::sendStatusEncoded(const char *keyword, const std::string &text) { if (d->nohup) { return; } if (const int err = assuan_write_status(d->ctx.get(), keyword, text.c_str())) { throw Exception(err, i18n("Cannot send \"%1\" status", QString::fromLatin1(keyword))); } } void AssuanCommand::sendData(const QByteArray &data, bool moreToCome) { if (d->nohup) { return; } if (const gpg_error_t err = assuan_send_data(d->ctx.get(), data.constData(), data.size())) { throw Exception(err, i18n("Cannot send data")); } if (!moreToCome) if (const gpg_error_t err = assuan_send_data(d->ctx.get(), nullptr, 0)) { // flush throw Exception(err, i18n("Cannot flush data")); } } int AssuanCommand::inquire(const char *keyword, QObject *receiver, const char *slot, unsigned int maxSize) { Q_ASSERT(keyword); Q_ASSERT(receiver); Q_ASSERT(slot); if (d->nohup) { return makeError(GPG_ERR_INV_OP); } #if defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) std::unique_ptr ih(new InquiryHandler(keyword, receiver)); receiver->connect(ih.get(), SIGNAL(signal(int,QByteArray,QByteArray)), slot); if (const gpg_error_t err = assuan_inquire_ext(d->ctx.get(), keyword, # if !defined(HAVE_ASSUAN2) && !defined(HAVE_NEW_STYLE_ASSUAN_INQUIRE_EXT) &ih->buffer, &ih->buflen, # endif maxSize, InquiryHandler::handler, ih.get())) { return err; } ih.release(); return 0; #else return makeError(GPG_ERR_NOT_SUPPORTED); // libassuan too old #endif // defined(HAVE_ASSUAN2) || defined(HAVE_ASSUAN_INQUIRE_EXT) } void AssuanCommand::done(const GpgME::Error &err, const QString &details) { if (d->ctx && !d->done && !details.isEmpty()) { qCDebug(KLEOPATRA_LOG) << "Error: " << details; d->utf8ErrorKeepAlive = details.toUtf8(); if (!d->nohup) { assuan_set_error(d->ctx.get(), err.encodedError(), d->utf8ErrorKeepAlive.constData()); } } done(err); } void AssuanCommand::done(const GpgME::Error &err) { if (!d->ctx) { qCDebug(KLEOPATRA_LOG) << err.asString() << ": called with NULL ctx."; return; } if (d->done) { qCDebug(KLEOPATRA_LOG) << err.asString() << ": called twice!"; return; } d->done = true; std::for_each(d->messages.begin(), d->messages.end(), std::mem_fn(&Input::finalize)); std::for_each(d->inputs.begin(), d->inputs.end(), std::mem_fn(&Input::finalize)); std::for_each(d->outputs.begin(), d->outputs.end(), std::mem_fn(&Output::finalize)); d->messages.clear(); d->inputs.clear(); d->outputs.clear(); d->files.clear(); // oh, hack :( Q_ASSERT(assuan_get_pointer(d->ctx.get())); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(d->ctx.get())); if (d->nohup) { conn.nohupDone(this); return; } const gpg_error_t rc = assuan_process_done(d->ctx.get(), err.encodedError()); if (gpg_err_code(rc) != GPG_ERR_NO_ERROR) qFatal("AssuanCommand::done: assuan_process_done returned error %d (%s)", static_cast(rc), gpg_strerror(rc)); d->utf8ErrorKeepAlive.clear(); conn.commandDone(this); } void AssuanCommand::setNohup(bool nohup) { d->nohup = nohup; } bool AssuanCommand::isNohup() const { return d->nohup; } bool AssuanCommand::isDone() const { return d->done; } QString AssuanCommand::sessionTitle() const { return d->sessionTitle; } unsigned int AssuanCommand::sessionId() const { return d->sessionId; } bool AssuanCommand::informativeSenders() const { return d->informativeSenders; } bool AssuanCommand::informativeRecipients() const { return d->informativeRecipients; } const std::vector &AssuanCommand::recipients() const { return d->recipients; } const std::vector &AssuanCommand::senders() const { return d->senders; } #ifndef HAVE_ASSUAN2 int AssuanCommandFactory::_handle(assuan_context_t ctx, char *line, const char *commandName) { #else gpg_error_t AssuanCommandFactory::_handle(assuan_context_t ctx, char *line, const char *commandName) { #endif Q_ASSERT(assuan_get_pointer(ctx)); AssuanServerConnection::Private &conn = *static_cast(assuan_get_pointer(ctx)); try { const auto it = std::lower_bound(conn.factories.begin(), conn.factories.end(), commandName, _detail::ByName()); kleo_assert(it != conn.factories.end()); kleo_assert(*it); kleo_assert(qstricmp((*it)->name(), commandName) == 0); const std::shared_ptr cmd = (*it)->create(); kleo_assert(cmd); cmd->d->ctx = conn.ctx; cmd->d->options = conn.options; cmd->d->inputs.swap(conn.inputs); kleo_assert(conn.inputs.empty()); cmd->d->messages.swap(conn.messages); kleo_assert(conn.messages.empty()); cmd->d->outputs.swap(conn.outputs); kleo_assert(conn.outputs.empty()); cmd->d->files.swap(conn.files); kleo_assert(conn.files.empty()); cmd->d->senders.swap(conn.senders); kleo_assert(conn.senders.empty()); cmd->d->recipients.swap(conn.recipients); kleo_assert(conn.recipients.empty()); cmd->d->informativeRecipients = conn.informativeRecipients; cmd->d->informativeSenders = conn.informativeSenders; cmd->d->bias = conn.bias; cmd->d->sessionTitle = conn.sessionTitle; cmd->d->sessionId = conn.sessionId; const std::map cmdline_options = parse_commandline(line); for (auto it = cmdline_options.begin(), end = cmdline_options.end(); it != end; ++it) { cmd->d->options[it->first] = QString::fromUtf8(it->second.c_str()); } bool nohup = false; if (cmd->d->options.count("nohup")) { if (!cmd->d->options["nohup"].toString().isEmpty()) { return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_ASS_PARAMETER), "--nohup takes no argument"); } nohup = true; cmd->d->options.erase("nohup"); } conn.currentCommand = cmd; conn.currentCommandIsNohup = nohup; QTimer::singleShot(0, &conn, &AssuanServerConnection::Private::startCommandBottomHalf); return 0; } catch (const Exception &e) { return assuan_process_done_msg(conn.ctx.get(), e.error_code(), e.message()); } catch (const std::exception &e) { return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), e.what()); } catch (...) { return assuan_process_done_msg(conn.ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), i18n("Caught unknown exception")); } } int AssuanServerConnection::Private::startCommandBottomHalf() { commandWaitingForCryptoCommandsEnabled = currentCommand && !cryptoCommandsEnabled; if (!cryptoCommandsEnabled) { return 0; } const std::shared_ptr cmd = currentCommand; if (!cmd) { return 0; } currentCommand.reset(); const bool nohup = currentCommandIsNohup; currentCommandIsNohup = false; try { if (const int err = cmd->start()) { if (cmd->isDone()) { return err; } else { return assuan_process_done(ctx.get(), err); } } if (cmd->isDone()) { return 0; } if (nohup) { cmd->setNohup(true); nohupedCommands.push_back(cmd); return assuan_process_done_msg(ctx.get(), 0, "Command put in the background to continue executing after connection end."); } else { currentCommand = cmd; return 0; } } catch (const Exception &e) { return assuan_process_done_msg(ctx.get(), e.error_code(), e.message()); } catch (const std::exception &e) { return assuan_process_done_msg(ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), e.what()); } catch (...) { return assuan_process_done_msg(ctx.get(), gpg_error(GPG_ERR_UNEXPECTED), i18n("Caught unknown exception")); } } // // // AssuanCommand convenience methods // // /*! Checks the \c --mode parameter. \returns The parameter as an AssuanCommand::Mode enum value. If no \c --mode was given, or it's value wasn't recognized, throws an Kleo::Exception. */ AssuanCommand::Mode AssuanCommand::checkMode() const { if (!hasOption("mode")) { throw Exception(makeError(GPG_ERR_MISSING_VALUE), i18n("Required --mode option missing")); } const QString modeString = option("mode").toString().toLower(); if (modeString == QLatin1String("filemanager")) { return FileManager; } if (modeString == QLatin1String("email")) { return EMail; } throw Exception(makeError(GPG_ERR_INV_ARG), i18n("invalid mode: \"%1\"", modeString)); } /*! Checks the \c --protocol parameter. \returns The parameter as a GpgME::Protocol enum value. If \c --protocol was given, but has an invalid value, throws an Kleo::Exception. If no \c --protocol was given, checks the connection bias, if available, otherwise, in FileManager mode, returns GpgME::UnknownProtocol, but if \a mode == \c EMail, throws an Kleo::Exception instead. */ GpgME::Protocol AssuanCommand::checkProtocol(Mode mode, int options) const { if (!hasOption("protocol")) if (d->bias != GpgME::UnknownProtocol) { return d->bias; } else if (mode == AssuanCommand::EMail && (options & AllowProtocolMissing) == 0) { throw Exception(makeError(GPG_ERR_MISSING_VALUE), i18n("Required --protocol option missing")); } else { return GpgME::UnknownProtocol; } else if (mode == AssuanCommand::FileManager) { throw Exception(makeError(GPG_ERR_INV_FLAG), i18n("--protocol is not allowed here")); } const QString protocolString = option("protocol").toString().toLower(); if (protocolString == QLatin1String("openpgp")) { return GpgME::OpenPGP; } if (protocolString == QLatin1String("cms")) { return GpgME::CMS; } throw Exception(makeError(GPG_ERR_INV_ARG), i18n("invalid protocol \"%1\"", protocolString)); } void AssuanCommand::doApplyWindowID(QWidget *widget) const { if (!widget || !hasOption("window-id")) { return; } apply_window_id(widget, option("window-id").toString()); } WId AssuanCommand::parentWId() const { return wid_from_string(option("window-id").toString()); } #include "assuanserverconnection.moc" diff --git a/src/uiserver/assuanserverconnection.h b/src/uiserver/assuanserverconnection.h index 25770b041..482dce8a6 100644 --- a/src/uiserver/assuanserverconnection.h +++ b/src/uiserver/assuanserverconnection.h @@ -1,49 +1,49 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/assuanserverconnection.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 // for assuan_fd_t #include #include #include #include namespace Kleo { class AssuanCommandFactory; class AssuanServerConnection : public QObject { Q_OBJECT public: AssuanServerConnection(assuan_fd_t fd, const std::vector< std::shared_ptr > &factories, QObject *parent = nullptr); - ~AssuanServerConnection(); + ~AssuanServerConnection() override; public Q_SLOTS: void enableCryptoCommands(bool enable = true); Q_SIGNALS: void closed(Kleo::AssuanServerConnection *which); void startKeyManagerRequested(); void startConfigDialogRequested(); public: class Private; private: kdtools::pimpl_ptr d; }; } diff --git a/src/uiserver/decryptverifycommandemailbase.cpp b/src/uiserver/decryptverifycommandemailbase.cpp index c57fafb19..349a7d39c 100644 --- a/src/uiserver/decryptverifycommandemailbase.cpp +++ b/src/uiserver/decryptverifycommandemailbase.cpp @@ -1,212 +1,212 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/decryptverifycommandemailbase.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 "decryptverifycommandemailbase.h" #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::Formatting; using namespace GpgME; class DecryptVerifyCommandEMailBase::Private : public QObject { Q_OBJECT friend class ::Kleo::DecryptVerifyCommandEMailBase; DecryptVerifyCommandEMailBase *const q; public: explicit Private(DecryptVerifyCommandEMailBase *qq) : QObject(), q(qq), controller() { } - ~Private() + ~Private() override { } void checkForErrors() const; public Q_SLOTS: void slotProgress(const QString &what, int current, int total); void verificationResult(const GpgME::VerificationResult &); void slotDone() { q->done(); } void slotError(int err, const QString &details) { q->done(err, details); } public: private: std::shared_ptr controller; }; DecryptVerifyCommandEMailBase::DecryptVerifyCommandEMailBase() : AssuanCommandMixin(), d(new Private(this)) { } DecryptVerifyCommandEMailBase::~DecryptVerifyCommandEMailBase() {} int DecryptVerifyCommandEMailBase::doStart() { d->checkForErrors(); d->controller.reset(new DecryptVerifyEMailController(shared_from_this())); const QString st = sessionTitle(); if (!st.isEmpty()) Q_FOREACH (const std::shared_ptr &i, inputs()) { i->setLabel(st); } d->controller->setSessionId(sessionId()); d->controller->setOperation(operation()); d->controller->setVerificationMode(messages().empty() ? Opaque : Detached); d->controller->setInputs(inputs()); d->controller->setSignedData(messages()); d->controller->setOutputs(outputs()); d->controller->setWizardShown(!hasOption("silent")); d->controller->setProtocol(checkProtocol(mode())); if (informativeSenders()) { d->controller->setInformativeSenders(senders()); } QObject::connect(d->controller.get(), SIGNAL(done()), d.get(), SLOT(slotDone()), Qt::QueuedConnection); QObject::connect(d->controller.get(), SIGNAL(error(int,QString)), d.get(), SLOT(slotError(int,QString)), Qt::QueuedConnection); QObject::connect(d->controller.get(), &DecryptVerifyEMailController::verificationResult, d.get(), &Private::verificationResult, Qt::QueuedConnection); d->controller->start(); return 0; } void DecryptVerifyCommandEMailBase::Private::checkForErrors() const { if (!q->senders().empty() && !q->informativeSenders()) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("Cannot use non-info SENDER")); if (!q->recipients().empty() && !q->informativeRecipients()) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("Cannot use non-info RECIPIENT")); // ### use informative recipients and senders const unsigned int numInputs = q->inputs().size(); const unsigned int numMessages = q->messages().size(); const unsigned int numOutputs = q->outputs().size(); const unsigned int numInformativeSenders = q->informativeSenders() ? q->senders().size() : 0; const DecryptVerifyOperation op = q->operation(); const GpgME::Protocol proto = q->checkProtocol(q->mode()); const unsigned int numFiles = q->numFiles(); if (numFiles) { throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("FILES present")); } if (!numInputs) throw Kleo::Exception(q->makeError(GPG_ERR_ASS_NO_INPUT), i18n("At least one INPUT needs to be provided")); if (numInformativeSenders != 0) if (numInformativeSenders != numInputs) throw Kleo::Exception(q->makeError(GPG_ERR_ASS_NO_INPUT), //TODO use better error code if possible i18n("INPUT/SENDER --info count mismatch")); if (numMessages) { if (numMessages != numInputs) throw Kleo::Exception(q->makeError(GPG_ERR_ASS_NO_INPUT), //TODO use better error code if possible i18n("INPUT/MESSAGE count mismatch")); else if (op != Verify) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("MESSAGE can only be given for detached signature verification")); } if (numOutputs) { if (numOutputs != numInputs) throw Kleo::Exception(q->makeError(GPG_ERR_ASS_NO_OUTPUT), //TODO use better error code if possible i18n("INPUT/OUTPUT count mismatch")); else if (numMessages) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("Cannot use OUTPUT and MESSAGE simultaneously")); } kleo_assert(proto != UnknownProtocol); const auto backend = (proto == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime(); if (!backend) throw Kleo::Exception(q->makeError(GPG_ERR_UNSUPPORTED_PROTOCOL), proto == OpenPGP ? i18n("No backend support for OpenPGP") : proto == CMS ? i18n("No backend support for S/MIME") : QString()); } void DecryptVerifyCommandEMailBase::doCanceled() { if (d->controller) { d->controller->cancel(); } } void DecryptVerifyCommandEMailBase::Private::slotProgress(const QString &what, int current, int total) { Q_UNUSED(what) Q_UNUSED(current) Q_UNUSED(total) // ### FIXME report progress, via sendStatus() } void DecryptVerifyCommandEMailBase::Private::verificationResult(const VerificationResult &vResult) { try { const std::vector sigs = vResult.signatures(); for (const Signature &sig : sigs) { const QString s = signatureToString(sig, sig.key(true, true)); const char *color = summaryToString(sig.summary()); q->sendStatusEncoded("SIGSTATUS", color + (' ' + hexencode(s.toUtf8().constData()))); } } catch (...) {} } #include "decryptverifycommandemailbase.moc" diff --git a/src/uiserver/decryptverifycommandfilesbase.cpp b/src/uiserver/decryptverifycommandfilesbase.cpp index 537860ce3..b6963f705 100644 --- a/src/uiserver/decryptverifycommandfilesbase.cpp +++ b/src/uiserver/decryptverifycommandfilesbase.cpp @@ -1,193 +1,193 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/decryptverifycommandfilesbase.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 "decryptverifycommandfilesbase.h" #include "fileoperationspreferences.h" #include #include "crypto/decryptverifyfilescontroller.h" #include "crypto/autodecryptverifyfilescontroller.h" #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::Formatting; using namespace GpgME; class DecryptVerifyCommandFilesBase::Private : public QObject { Q_OBJECT friend class ::Kleo::DecryptVerifyCommandFilesBase; DecryptVerifyCommandFilesBase *const q; public: explicit Private(DecryptVerifyCommandFilesBase *qq) : QObject(), q(qq), controller() { } - ~Private() + ~Private() override { } void checkForErrors() const; public Q_SLOTS: void slotProgress(const QString &what, int current, int total); void verificationResult(const GpgME::VerificationResult &); void slotDone() { q->done(); } void slotError(int err, const QString &details) { q->done(err, details); } public: private: std::shared_ptr controller; }; DecryptVerifyCommandFilesBase::DecryptVerifyCommandFilesBase() : AssuanCommandMixin(), d(new Private(this)) { } DecryptVerifyCommandFilesBase::~DecryptVerifyCommandFilesBase() {} int DecryptVerifyCommandFilesBase::doStart() { d->checkForErrors(); FileOperationsPreferences prefs; if (prefs.autoDecryptVerify()) { d->controller.reset(new AutoDecryptVerifyFilesController()); } else { d->controller.reset(new DecryptVerifyFilesController(shared_from_this())); } d->controller->setOperation(operation()); d->controller->setFiles(fileNames()); QObject::connect(d->controller.get(), SIGNAL(done()), d.get(), SLOT(slotDone()), Qt::QueuedConnection); QObject::connect(d->controller.get(), SIGNAL(error(int,QString)), d.get(), SLOT(slotError(int,QString)), Qt::QueuedConnection); QObject::connect(d->controller.get(), &DecryptVerifyFilesController::verificationResult, d.get(), &Private::verificationResult, Qt::QueuedConnection); d->controller->start(); return 0; } namespace { struct is_file : std::unary_function { bool operator()(const QString &file) const { return QFileInfo(file).isFile(); } }; } void DecryptVerifyCommandFilesBase::Private::checkForErrors() const { if (!q->senders().empty()) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("Cannot use SENDER")); if (!q->recipients().empty()) throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("Cannot use RECIPIENT")); const unsigned int numInputs = q->inputs().size(); const unsigned int numMessages = q->messages().size(); const unsigned int numOutputs = q->outputs().size(); if (numInputs) { throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("INPUT present")); } if (numMessages) { throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("MESSAGE present")); } if (numOutputs) { throw Kleo::Exception(q->makeError(GPG_ERR_CONFLICT), i18n("OUTPUT present")); } const QStringList fileNames = q->fileNames(); if (fileNames.empty()) throw Exception(makeError(GPG_ERR_ASS_NO_INPUT), i18n("At least one FILE must be present")); if (!std::all_of(fileNames.cbegin(), fileNames.cend(), is_file())) throw Exception(makeError(GPG_ERR_INV_ARG), i18n("DECRYPT/VERIFY_FILES cannot use directories as input")); } void DecryptVerifyCommandFilesBase::doCanceled() { if (d->controller) { d->controller->cancel(); } } void DecryptVerifyCommandFilesBase::Private::slotProgress(const QString &what, int current, int total) { Q_UNUSED(what) Q_UNUSED(current) Q_UNUSED(total) // ### FIXME report progress, via sendStatus() } void DecryptVerifyCommandFilesBase::Private::verificationResult(const VerificationResult &vResult) { try { const std::vector sigs = vResult.signatures(); for (const Signature &sig : sigs) { const QString s = signatureToString(sig, sig.key(true, true)); const char *color = summaryToString(sig.summary()); q->sendStatusEncoded("SIGSTATUS", color + (' ' + hexencode(s.toUtf8().constData()))); } } catch (...) {} } #include "decryptverifycommandfilesbase.moc" diff --git a/src/uiserver/prepsigncommand.h b/src/uiserver/prepsigncommand.h index b040416c6..909b7da80 100644 --- a/src/uiserver/prepsigncommand.h +++ b/src/uiserver/prepsigncommand.h @@ -1,39 +1,39 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/prepsigncommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "assuancommand.h" #include namespace Kleo { class PrepSignCommand : public Kleo::AssuanCommandMixin { public: PrepSignCommand(); - virtual ~PrepSignCommand(); + ~PrepSignCommand() override; private: int doStart() override; void doCanceled() override; public: static const char *staticName() { return "PREP_SIGN"; } class Private; private: kdtools::pimpl_ptr d; }; } diff --git a/src/uiserver/signencryptfilescommand.h b/src/uiserver/signencryptfilescommand.h index 76ad6dcba..8be858c5b 100644 --- a/src/uiserver/signencryptfilescommand.h +++ b/src/uiserver/signencryptfilescommand.h @@ -1,95 +1,95 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/signencryptfilescommand.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 "assuancommand.h" #include namespace Kleo { class SignEncryptFilesCommand : public Kleo::AssuanCommandMixin { public: SignEncryptFilesCommand(); - virtual ~SignEncryptFilesCommand(); + ~SignEncryptFilesCommand() override; protected: enum Operation { SignDisallowed = 0, SignAllowed = 1, SignSelected = 2, SignMask = SignAllowed | SignSelected, EncryptDisallowed = 0, EncryptAllowed = 4, EncryptSelected = 8, EncryptMask = EncryptAllowed | EncryptSelected }; private: virtual unsigned int operation() const { return SignSelected | EncryptSelected; } private: int doStart() override; void doCanceled() override; public: static const char *staticName() { return "SIGN_ENCRYPT_FILES"; } class Private; private: kdtools::pimpl_ptr d; }; class EncryptSignFilesCommand : public Kleo::AssuanCommandMixin { public: static const char *staticName() { return "ENCRYPT_SIGN_FILES"; } }; class EncryptFilesCommand : public Kleo::AssuanCommandMixin { public: static const char *staticName() { return "ENCRYPT_FILES"; } unsigned int operation() const override { return SignAllowed | EncryptSelected; } }; class SignFilesCommand : public Kleo::AssuanCommandMixin { public: static const char *staticName() { return "SIGN_FILES"; } unsigned int operation() const override { return SignSelected | EncryptAllowed; } }; } diff --git a/src/uiserver/uiserver.h b/src/uiserver/uiserver.h index 72e48c587..b0ae88bc6 100644 --- a/src/uiserver/uiserver.h +++ b/src/uiserver/uiserver.h @@ -1,60 +1,60 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/uiserver.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 class QString; namespace Kleo { class AssuanCommandFactory; class UiServer : public QObject { Q_OBJECT public: explicit UiServer(const QString &socket, QObject *parent = nullptr); - ~UiServer(); + ~UiServer() override; static void setLogStream(FILE *file); bool registerCommandFactory(const std::shared_ptr &cmdFactory); bool waitForStopped(unsigned int ms = 0xFFFFFFFF); bool isStopped() const; bool isStopping() const; QString socketName() const; public Q_SLOTS: void start(); void stop(); void enableCryptoCommands(bool enable = true); Q_SIGNALS: void stopped(); void startKeyManagerRequested(); void startConfigDialogRequested(); private: class Private; kdtools::pimpl_ptr d; }; } diff --git a/src/uiserver/verifychecksumscommand.h b/src/uiserver/verifychecksumscommand.h index d0d91e254..776b0b835 100644 --- a/src/uiserver/verifychecksumscommand.h +++ b/src/uiserver/verifychecksumscommand.h @@ -1,53 +1,53 @@ /* -*- mode: c++; c-basic-offset:4 -*- uiserver/verifychecksumscommand.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include "assuancommand.h" #ifndef QT_NO_DIRMODEL #include namespace Kleo { class VerifyChecksumsCommand : public QObject, public AssuanCommandMixin { Q_OBJECT public: VerifyChecksumsCommand(); - ~VerifyChecksumsCommand(); + ~VerifyChecksumsCommand() override; static const char *staticName() { return "CHECKSUM_VERIFY_FILES"; } private: int doStart() override; void doCanceled() override; #ifdef Q_MOC_RUN private Q_SLOTS: void done(); void done(int, QString); #endif private: class Private; kdtools::pimpl_ptr d; //Q_PRIVATE_SLOT( this, void done() ) //Q_PRIVATE_SLOT( this, void done(int,QString) ) }; } #endif // QT_NO_DIRMODEL diff --git a/src/utils/archivedefinition.cpp b/src/utils/archivedefinition.cpp index 3e25ce5bc..7405d23f3 100644 --- a/src/utils/archivedefinition.cpp +++ b/src/utils/archivedefinition.cpp @@ -1,415 +1,415 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/archivedefinition.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009, 2010 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "archivedefinition.h" #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include using namespace GpgME; using namespace Kleo; static QMutex installPathMutex; Q_GLOBAL_STATIC(QString, _installPath) QString ArchiveDefinition::installPath() { const QMutexLocker locker(&installPathMutex); QString *const ip = _installPath(); if (ip->isEmpty()) { if (QCoreApplication::instance()) { *ip = QCoreApplication::applicationDirPath(); } else { qCWarning(KLEOPATRA_LOG) << "called before QCoreApplication was constructed"; } } return *ip; } void ArchiveDefinition::setInstallPath(const QString &ip) { const QMutexLocker locker(&installPathMutex); *_installPath() = ip; } // Archive Definition #N groups static const QLatin1String ID_ENTRY("id"); static const QLatin1String NAME_ENTRY("Name"); static const QLatin1String PACK_COMMAND_ENTRY("pack-command"); static const QLatin1String PACK_COMMAND_OPENPGP_ENTRY("pack-command-openpgp"); static const QLatin1String PACK_COMMAND_CMS_ENTRY("pack-command-cms"); static const QLatin1String UNPACK_COMMAND_ENTRY("unpack-command"); static const QLatin1String UNPACK_COMMAND_OPENPGP_ENTRY("unpack-command-openpgp"); static const QLatin1String UNPACK_COMMAND_CMS_ENTRY("unpack-command-cms"); static const QLatin1String EXTENSIONS_ENTRY("extensions"); static const QLatin1String EXTENSIONS_OPENPGP_ENTRY("extensions-openpgp"); static const QLatin1String EXTENSIONS_CMS_ENTRY("extensions-cms"); static const QLatin1String FILE_PLACEHOLDER("%f"); static const QLatin1String FILE_PLACEHOLDER_7BIT("%F"); static const QLatin1String INSTALLPATH_PLACEHOLDER("%I"); static const QLatin1String NULL_SEPARATED_STDIN_INDICATOR("0|"); static const QLatin1Char NEWLINE_SEPARATED_STDIN_INDICATOR('|'); namespace { class ArchiveDefinitionError : public Kleo::Exception { const QString m_id; public: ArchiveDefinitionError(const QString &id, const QString &message) : Kleo::Exception(GPG_ERR_INV_PARAMETER, i18n("Error in archive definition %1: %2", id, message), MessageOnly), m_id(id) { } - ~ArchiveDefinitionError() throw() {} + ~ArchiveDefinitionError() throw() override {} const QString &archiveDefinitionId() const { return m_id; } }; } static QString try_extensions(const QString &path) { static const char exts[][4] = { "", "exe", "bat", "bin", "cmd", }; static const size_t numExts = sizeof exts / sizeof * exts; for (unsigned int i = 0; i < numExts; ++i) { const QFileInfo fi(path + QLatin1Char('.') + QLatin1String(exts[i])); if (fi.exists()) { return fi.filePath(); } } return QString(); } static void parse_command(QString cmdline, const QString &id, const QString &whichCommand, QString *command, QStringList *prefix, QStringList *suffix, ArchiveDefinition::ArgumentPassingMethod *method, bool parseFilePlaceholder) { Q_ASSERT(prefix); Q_ASSERT(suffix); Q_ASSERT(method); KShell::Errors errors; QStringList l; if (cmdline.startsWith(NULL_SEPARATED_STDIN_INDICATOR)) { *method = ArchiveDefinition::NullSeparatedInputFile; cmdline.remove(0, 2); } else if (cmdline.startsWith(NEWLINE_SEPARATED_STDIN_INDICATOR)) { *method = ArchiveDefinition::NewlineSeparatedInputFile; cmdline.remove(0, 1); } else { *method = ArchiveDefinition::CommandLine; } if (*method != ArchiveDefinition::CommandLine && cmdline.contains(FILE_PLACEHOLDER)) { throw ArchiveDefinitionError(id, i18n("Cannot use both %f and | in '%1'", whichCommand)); } cmdline.replace(FILE_PLACEHOLDER, QLatin1String("__files_go_here__")) .replace(INSTALLPATH_PLACEHOLDER, QStringLiteral("__path_goes_here__")) .replace(FILE_PLACEHOLDER_7BIT, QStringLiteral("__file7Bit_go_here__")); l = KShell::splitArgs(cmdline, KShell::AbortOnMeta | KShell::TildeExpand, &errors); l = l.replaceInStrings(QStringLiteral("__files_go_here__"), FILE_PLACEHOLDER); l = l.replaceInStrings(QStringLiteral("__file7Bit_go_here__"), FILE_PLACEHOLDER_7BIT); if (l.indexOf(QRegExp(QLatin1String(".*__path_goes_here__.*"))) >= 0) { l = l.replaceInStrings(QStringLiteral("__path_goes_here__"), ArchiveDefinition::installPath()); } if (errors == KShell::BadQuoting) { throw ArchiveDefinitionError(id, i18n("Quoting error in '%1' entry", whichCommand)); } if (errors == KShell::FoundMeta) { throw ArchiveDefinitionError(id, i18n("'%1' too complex (would need shell)", whichCommand)); } qCDebug(KLEOPATRA_LOG) << "ArchiveDefinition[" << id << ']' << l; if (l.empty()) { throw ArchiveDefinitionError(id, i18n("'%1' entry is empty/missing", whichCommand)); } const QFileInfo fi1(l.front()); if (fi1.isAbsolute()) { *command = try_extensions(l.front()); } else { *command = QStandardPaths::findExecutable(fi1.fileName()); } if (command->isEmpty()) { throw ArchiveDefinitionError(id, i18n("'%1' empty or not found", whichCommand)); } if (parseFilePlaceholder) { const int idx1 = l.indexOf(FILE_PLACEHOLDER); if (idx1 < 0) { // none -> append *prefix = l.mid(1); } else { *prefix = l.mid(1, idx1 - 1); *suffix = l.mid(idx1 + 1); } } else { *prefix = l.mid(1); } switch (*method) { case ArchiveDefinition::CommandLine: qCDebug(KLEOPATRA_LOG) << "ArchiveDefinition[" << id << ']' << *command << *prefix << FILE_PLACEHOLDER << *suffix; break; case ArchiveDefinition::NewlineSeparatedInputFile: qCDebug(KLEOPATRA_LOG) << "ArchiveDefinition[" << id << ']' << "find | " << *command << *prefix; break; case ArchiveDefinition::NullSeparatedInputFile: qCDebug(KLEOPATRA_LOG) << "ArchiveDefinition[" << id << ']' << "find -print0 | " << *command << *prefix; break; case ArchiveDefinition::NumArgumentPassingMethods: Q_ASSERT(!"Should not happen"); break; } } namespace { class KConfigBasedArchiveDefinition : public ArchiveDefinition { public: explicit KConfigBasedArchiveDefinition(const KConfigGroup &group) : ArchiveDefinition(group.readEntryUntranslated(ID_ENTRY), group.readEntry(NAME_ENTRY)) { if (id().isEmpty()) { throw ArchiveDefinitionError(group.name(), i18n("'%1' entry is empty/missing", ID_ENTRY)); } QStringList extensions; QString extensionsKey; // extensions(-openpgp) if (group.hasKey(EXTENSIONS_OPENPGP_ENTRY)) { extensionsKey = EXTENSIONS_OPENPGP_ENTRY; } else { extensionsKey = EXTENSIONS_ENTRY; } extensions = group.readEntry(extensionsKey, QStringList()); if (extensions.empty()) { throw ArchiveDefinitionError(id(), i18n("'%1' entry is empty/missing", extensionsKey)); } setExtensions(OpenPGP, extensions); // extensions(-cms) if (group.hasKey(EXTENSIONS_CMS_ENTRY)) { extensionsKey = EXTENSIONS_CMS_ENTRY; } else { extensionsKey = EXTENSIONS_ENTRY; } extensions = group.readEntry(extensionsKey, QStringList()); if (extensions.empty()) { throw ArchiveDefinitionError(id(), i18n("'%1' entry is empty/missing", extensionsKey)); } setExtensions(CMS, extensions); ArgumentPassingMethod method; // pack-command(-openpgp) if (group.hasKey(PACK_COMMAND_OPENPGP_ENTRY)) parse_command(group.readEntry(PACK_COMMAND_OPENPGP_ENTRY), id(), PACK_COMMAND_OPENPGP_ENTRY, &m_packCommand[OpenPGP], &m_packPrefixArguments[OpenPGP], &m_packPostfixArguments[OpenPGP], &method, true); else parse_command(group.readEntry(PACK_COMMAND_ENTRY), id(), PACK_COMMAND_ENTRY, &m_packCommand[OpenPGP], &m_packPrefixArguments[OpenPGP], &m_packPostfixArguments[OpenPGP], &method, true); setPackCommandArgumentPassingMethod(OpenPGP, method); // pack-command(-cms) if (group.hasKey(PACK_COMMAND_CMS_ENTRY)) parse_command(group.readEntry(PACK_COMMAND_CMS_ENTRY), id(), PACK_COMMAND_CMS_ENTRY, &m_packCommand[CMS], &m_packPrefixArguments[CMS], &m_packPostfixArguments[CMS], &method, true); else parse_command(group.readEntry(PACK_COMMAND_ENTRY), id(), PACK_COMMAND_ENTRY, &m_packCommand[CMS], &m_packPrefixArguments[CMS], &m_packPostfixArguments[CMS], &method, true); setPackCommandArgumentPassingMethod(CMS, method); QStringList dummy; // unpack-command(-openpgp) if (group.hasKey(UNPACK_COMMAND_OPENPGP_ENTRY)) parse_command(group.readEntry(UNPACK_COMMAND_OPENPGP_ENTRY), id(), UNPACK_COMMAND_OPENPGP_ENTRY, &m_unpackCommand[OpenPGP], &m_unpackArguments[OpenPGP], &dummy, &method, false); else parse_command(group.readEntry(UNPACK_COMMAND_ENTRY), id(), UNPACK_COMMAND_ENTRY, &m_unpackCommand[OpenPGP], &m_unpackArguments[OpenPGP], &dummy, &method, false); if (method != CommandLine) { throw ArchiveDefinitionError(id(), i18n("cannot use argument passing on standard input for unpack-command")); } // unpack-command(-cms) if (group.hasKey(UNPACK_COMMAND_CMS_ENTRY)) parse_command(group.readEntry(UNPACK_COMMAND_CMS_ENTRY), id(), UNPACK_COMMAND_CMS_ENTRY, &m_unpackCommand[CMS], &m_unpackArguments[CMS], &dummy, &method, false); else parse_command(group.readEntry(UNPACK_COMMAND_ENTRY), id(), UNPACK_COMMAND_ENTRY, &m_unpackCommand[CMS], &m_unpackArguments[CMS], &dummy, &method, false); if (method != CommandLine) { throw ArchiveDefinitionError(id(), i18n("cannot use argument passing on standard input for unpack-command")); } } private: QString doGetPackCommand(GpgME::Protocol p) const override { return m_packCommand[p]; } QString doGetUnpackCommand(GpgME::Protocol p) const override { return m_unpackCommand[p]; } QStringList doGetPackArguments(GpgME::Protocol p, const QStringList &files) const override { return m_packPrefixArguments[p] + files + m_packPostfixArguments[p]; } QStringList doGetUnpackArguments(GpgME::Protocol p, const QString &file) const override { QStringList copy = m_unpackArguments[p]; if (copy.contains(FILE_PLACEHOLDER_7BIT)) { /* This is a crutch for missing a way to provide Unicode arguments * to gpgtar unless gpgtar offers a unicode interface we have * no defined way to provide non 7Bit arguments. So we filter out * the chars and replace them by _ to avoid completely broken * folder names when unpacking. This is only relevant for the * unpacked folder and does not effect files in the archive. */ const QRegExp non7Bit(QStringLiteral("[^\\x{0000}-\\x{007F}]")); QString underscore_filename = file; underscore_filename.replace(non7Bit, QStringLiteral("_")); copy.replaceInStrings(FILE_PLACEHOLDER_7BIT, underscore_filename); } copy.replaceInStrings(FILE_PLACEHOLDER, file); return copy; } private: QString m_packCommand[2], m_unpackCommand[2]; QStringList m_packPrefixArguments[2], m_packPostfixArguments[2]; QStringList m_unpackArguments[2]; }; } ArchiveDefinition::ArchiveDefinition(const QString &id, const QString &label) : m_id(id), m_label(label) { m_packCommandMethod[GpgME::OpenPGP] = m_packCommandMethod[GpgME::CMS] = CommandLine; } ArchiveDefinition::~ArchiveDefinition() {} static QByteArray make_input(const QStringList &files, char sep) { QByteArray result; for (const QString &file : files) { #ifdef Q_OS_WIN // As encoding is more complicated on windows with different // 8 bit codepages we always use UTF-8 here and add this as an // option in the libkleopatrarc.desktop archive definition. result += file.toUtf8(); #else result += QFile::encodeName(file); #endif result += sep; } return result; } std::shared_ptr ArchiveDefinition::createInputFromPackCommand(GpgME::Protocol p, const QStringList &files) const { checkProtocol(p); const QString base = heuristicBaseDirectory(files); if (base.isEmpty()) { throw Kleo::Exception(GPG_ERR_CONFLICT, i18n("Cannot find common base directory for these files:\n%1", files.join(QLatin1Char('\n')))); } qCDebug(KLEOPATRA_LOG) << "heuristicBaseDirectory(" << files << ") ->" << base; const QStringList relative = makeRelativeTo(base, files); qCDebug(KLEOPATRA_LOG) << "relative" << relative; switch (m_packCommandMethod[p]) { case CommandLine: return Input::createFromProcessStdOut(doGetPackCommand(p), doGetPackArguments(p, relative), QDir(base)); case NewlineSeparatedInputFile: return Input::createFromProcessStdOut(doGetPackCommand(p), doGetPackArguments(p, QStringList()), QDir(base), make_input(relative, '\n')); case NullSeparatedInputFile: return Input::createFromProcessStdOut(doGetPackCommand(p), doGetPackArguments(p, QStringList()), QDir(base), make_input(relative, '\0')); case NumArgumentPassingMethods: Q_ASSERT(!"Should not happen"); } return std::shared_ptr(); // make compiler happy } std::shared_ptr ArchiveDefinition::createOutputFromUnpackCommand(GpgME::Protocol p, const QString &file, const QDir &wd) const { checkProtocol(p); const QFileInfo fi(file); return Output::createFromProcessStdIn(doGetUnpackCommand(p), doGetUnpackArguments(p, fi.absoluteFilePath()), wd); } // static std::vector< std::shared_ptr > ArchiveDefinition::getArchiveDefinitions() { QStringList errors; return getArchiveDefinitions(errors); } // static std::vector< std::shared_ptr > ArchiveDefinition::getArchiveDefinitions(QStringList &errors) { std::vector< std::shared_ptr > result; KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("libkleopatrarc")); const QStringList groups = config->groupList().filter(QRegularExpression(QStringLiteral("^Archive Definition #"))); result.reserve(groups.size()); for (const QString &group : groups) try { const std::shared_ptr ad(new KConfigBasedArchiveDefinition(KConfigGroup(config, group))); result.push_back(ad); } catch (const std::exception &e) { qCDebug(KLEOPATRA_LOG) << e.what(); errors.push_back(QString::fromLocal8Bit(e.what())); } catch (...) { errors.push_back(i18n("Caught unknown exception in group %1", group)); } return result; } void ArchiveDefinition::checkProtocol(GpgME::Protocol p) const { kleo_assert(p == GpgME::OpenPGP || p == GpgME::CMS); } diff --git a/src/utils/clipboardmenu.h b/src/utils/clipboardmenu.h index 30f7668fc..f3359b39c 100644 --- a/src/utils/clipboardmenu.h +++ b/src/utils/clipboardmenu.h @@ -1,47 +1,47 @@ /* SPDX-FileCopyrightText: 2014-2021 Laurent Montel SPDX-License-Identifier: GPL-2.0-only */ #pragma once #include class KActionMenu; class QAction; class MainWindow; namespace Kleo { class Command; } class ClipboardMenu : public QObject { Q_OBJECT public: explicit ClipboardMenu(QObject *parent = nullptr); - ~ClipboardMenu(); + ~ClipboardMenu() override; void setMainWindow(MainWindow *window); KActionMenu *clipboardMenu() const; private Q_SLOTS: void slotImportClipboard(); void slotEncryptClipboard(); void slotOpenPGPSignClipboard(); void slotSMIMESignClipboard(); void slotDecryptVerifyClipboard(); void slotEnableDisableActions(); private: void startCommand(Kleo::Command *cmd); KActionMenu *mClipboardMenu; QAction *mImportClipboardAction; QAction *mEncryptClipboardAction; QAction *mSmimeSignClipboardAction; QAction *mOpenPGPSignClipboardAction; QAction *mDecryptVerifyClipboardAction; MainWindow *mWindow; }; diff --git a/src/utils/headerview.h b/src/utils/headerview.h index 7b0ae5f53..b8e3993a7 100644 --- a/src/utils/headerview.h +++ b/src/utils/headerview.h @@ -1,44 +1,44 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/headerview.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 #include #include namespace Kleo { class HeaderView : public QHeaderView { Q_OBJECT public: explicit HeaderView(Qt::Orientation o, QWidget *parent = nullptr); - ~HeaderView(); + ~HeaderView() override; void setSectionSizes(const std::vector &sizes); std::vector sectionSizes() const; private: //@{ /*! Defined, but not implemented, to catch at least some usage errors */ void setResizeMode(int, ResizeMode); //@} private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void _klhv_slotSectionCountChanged(int, int)) Q_PRIVATE_SLOT(d, void _klhv_slotSectionResized(int, int, int)) }; } diff --git a/src/utils/input.cpp b/src/utils/input.cpp index 7cef7f162..4857133e0 100644 --- a/src/utils/input.cpp +++ b/src/utils/input.cpp @@ -1,460 +1,460 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/input.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 "input.h" #include "input_p.h" #include "detail_p.h" #include "kdpipeiodevice.h" #include "windowsprocessdevice.h" #include "log.h" #include "kleo_assert.h" #include "cached.h" #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Kleo; namespace { class PipeInput : public InputImplBase { public: explicit PipeInput(assuan_fd_t fd); std::shared_ptr ioDevice() const override { return m_io; } unsigned int classification() const override; unsigned long long size() const override { return 0; } private: std::shared_ptr m_io; }; class ProcessStdOutInput : public InputImplBase { public: - ~ProcessStdOutInput() + ~ProcessStdOutInput() override { finalize(); } explicit ProcessStdOutInput(const QString &cmd, const QStringList &args, const QDir &wd, const QByteArray &stdin_ = QByteArray()); std::shared_ptr ioDevice() const override { return m_proc; } unsigned int classification() const override { return 0U; // plain text } unsigned long long size() const override { return 0; } QString label() const override; bool failed() const override; private: QString doErrorString() const override; private: const QString m_command; const QStringList m_arguments; #ifdef Q_OS_WIN std::shared_ptr m_proc; #else std::shared_ptr m_proc; #endif }; class FileInput : public InputImplBase { public: explicit FileInput(const QString &fileName); explicit FileInput(const std::shared_ptr &file); QString label() const override { return m_io ? QFileInfo(m_fileName).fileName() : InputImplBase::label(); } std::shared_ptr ioDevice() const override { return m_io; } unsigned int classification() const override; unsigned long long size() const override { return QFileInfo(m_fileName).size(); } private: std::shared_ptr m_io; QString m_fileName; }; #ifndef QT_NO_CLIPBOARD class ClipboardInput : public Input { public: explicit ClipboardInput(QClipboard::Mode mode); void setLabel(const QString &label) override; QString label() const override; std::shared_ptr ioDevice() const override { return m_buffer; } unsigned int classification() const override; unsigned long long size() const override { return m_buffer ? m_buffer->buffer().size() : 0; } QString errorString() const override { return QString(); } private: const QClipboard::Mode m_mode; std::shared_ptr m_buffer; }; #endif // QT_NO_CLIPBOARD class ByteArrayInput: public Input { public: explicit ByteArrayInput(QByteArray *data): m_buffer(std::shared_ptr(new QBuffer(data))) { if (!m_buffer->open(QIODevice::ReadOnly)) throw Exception(gpg_error(GPG_ERR_EIO), QStringLiteral("Could not open bytearray for reading?!")); } void setLabel(const QString &label) override { m_label = label; } QString label() const override { return m_label; } std::shared_ptr ioDevice() const override { return m_buffer; } unsigned long long size() const override { return m_buffer ? m_buffer->buffer().size() : 0; } QString errorString() const override { return QString(); } unsigned int classification() const override { return classifyContent(m_buffer->data()); } private: std::shared_ptr m_buffer; QString m_label; }; } std::shared_ptr Input::createFromByteArray(QByteArray *data, const QString &label) { std::shared_ptr po(new ByteArrayInput(data)); po->setLabel(label); return po; } std::shared_ptr Input::createFromPipeDevice(assuan_fd_t fd, const QString &label) { std::shared_ptr po(new PipeInput(fd)); po->setDefaultLabel(label); return po; } PipeInput::PipeInput(assuan_fd_t fd) : InputImplBase(), m_io() { std::shared_ptr kdp(new KDPipeIODevice); errno = 0; if (!kdp->open(fd, QIODevice::ReadOnly)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not open FD %1 for reading", _detail::assuanFD2int(fd))); m_io = Log::instance()->createIOLogger(kdp, QStringLiteral("pipe-input"), Log::Read); } unsigned int PipeInput::classification() const { notImplemented(); return 0; } std::shared_ptr Input::createFromFile(const QString &fileName, bool) { return std::shared_ptr(new FileInput(fileName)); } std::shared_ptr Input::createFromFile(const std::shared_ptr &file) { return std::shared_ptr(new FileInput(file)); } FileInput::FileInput(const QString &fileName) : InputImplBase(), m_io(), m_fileName(fileName) { std::shared_ptr file(new QFile(fileName)); errno = 0; if (!file->open(QIODevice::ReadOnly)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not open file \"%1\" for reading", fileName)); m_io = Log::instance()->createIOLogger(file, QStringLiteral("file-in"), Log::Read); } FileInput::FileInput(const std::shared_ptr &file) : InputImplBase(), m_io(), m_fileName(file->fileName()) { kleo_assert(file); errno = 0; if (file->isOpen() && !file->isReadable()) throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("File \"%1\" is already open, but not for reading", file->fileName())); if (!file->isOpen() && !file->open(QIODevice::ReadOnly)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not open file \"%1\" for reading", m_fileName)); m_io = Log::instance()->createIOLogger(file, QStringLiteral("file-in"), Log::Read); } unsigned int FileInput::classification() const { return classify(m_fileName); } std::shared_ptr Input::createFromProcessStdOut(const QString &command) { return std::shared_ptr(new ProcessStdOutInput(command, QStringList(), QDir::current())); } std::shared_ptr Input::createFromProcessStdOut(const QString &command, const QStringList &args) { return std::shared_ptr(new ProcessStdOutInput(command, args, QDir::current())); } std::shared_ptr Input::createFromProcessStdOut(const QString &command, const QStringList &args, const QDir &wd) { return std::shared_ptr(new ProcessStdOutInput(command, args, wd)); } std::shared_ptr Input::createFromProcessStdOut(const QString &command, const QByteArray &stdin_) { return std::shared_ptr(new ProcessStdOutInput(command, QStringList(), QDir::current(), stdin_)); } std::shared_ptr Input::createFromProcessStdOut(const QString &command, const QStringList &args, const QByteArray &stdin_) { return std::shared_ptr(new ProcessStdOutInput(command, args, QDir::current(), stdin_)); } std::shared_ptr Input::createFromProcessStdOut(const QString &command, const QStringList &args, const QDir &wd, const QByteArray &stdin_) { return std::shared_ptr(new ProcessStdOutInput(command, args, wd, stdin_)); } namespace { struct Outputter { const QByteArray &data; explicit Outputter(const QByteArray &data) : data(data) {} }; static QDebug operator<<(QDebug s, const Outputter &o) { if (const quint64 size = o.data.size()) { s << " << (" << size << "bytes)"; } return s; } } ProcessStdOutInput::ProcessStdOutInput(const QString &cmd, const QStringList &args, const QDir &wd, const QByteArray &stdin_) : InputImplBase(), m_command(cmd), m_arguments(args) { const QIODevice::OpenMode openMode = stdin_.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite; qCDebug(KLEOPATRA_LOG) << "cd" << wd.absolutePath() << '\n' << cmd << args << Outputter(stdin_); if (cmd.isEmpty()) throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Command not specified")); #ifndef Q_OS_WIN m_proc = std::shared_ptr (new QProcess); m_proc->setWorkingDirectory(wd.absolutePath()); m_proc->start(cmd, args, openMode); if (!m_proc->waitForStarted()) throw Exception(gpg_error(GPG_ERR_EIO), i18n("Could not start %1 process: %2", cmd, m_proc->errorString())); #else m_proc = std::shared_ptr (new WindowsProcessDevice(cmd, args, wd.absolutePath())); if (!m_proc->open(openMode)) { throw Exception(gpg_error(GPG_ERR_EIO), i18n("Could not start %1 process: %2", cmd, m_proc->errorString())); } #endif if (!stdin_.isEmpty()) { if (m_proc->write(stdin_) != stdin_.size()) throw Exception(gpg_error(GPG_ERR_EIO), i18n("Failed to write input to %1 process: %2", cmd, m_proc->errorString())); m_proc->closeWriteChannel(); } } QString ProcessStdOutInput::label() const { if (!m_proc) { return InputImplBase::label(); } // output max. 3 arguments const QString cmdline = (QStringList(m_command) + m_arguments.mid(0, 3)).join(QLatin1Char(' ')); if (m_arguments.size() > 3) { return i18nc("e.g. \"Output of tar xf - file1 ...\"", "Output of %1 ...", cmdline); } else { return i18nc("e.g. \"Output of tar xf - file\"", "Output of %1", cmdline); } } QString ProcessStdOutInput::doErrorString() const { kleo_assert(m_proc); #ifdef Q_OS_WIN const auto err = m_proc->errorString(); if (!err.isEmpty()) { return QStringLiteral("%1:\n%2").arg(m_command).arg(err); } return QString(); #else if (m_proc->exitStatus() == QProcess::NormalExit && m_proc->exitCode() == 0) { return QString(); } if (m_proc->error() == QProcess::UnknownError) return i18n("Error while running %1:\n%2", m_command, QString::fromLocal8Bit(m_proc->readAllStandardError().trimmed().constData())); else { return i18n("Failed to execute %1: %2", m_command, m_proc->errorString()); } #endif } bool ProcessStdOutInput::failed() const { kleo_assert(m_proc); #ifdef Q_OS_WIN return !m_proc->errorString().isEmpty(); #else return !(m_proc->exitStatus() == QProcess::NormalExit && m_proc->exitCode() == 0); #endif } #ifndef QT_NO_CLIPBOARD std::shared_ptr Input::createFromClipboard() { return std::shared_ptr(new ClipboardInput(QClipboard::Clipboard)); } static QByteArray dataFromClipboard(QClipboard::Mode mode) { Q_UNUSED(mode) if (QClipboard *const cb = QApplication::clipboard()) { return cb->text().toUtf8(); } else { return QByteArray(); } } ClipboardInput::ClipboardInput(QClipboard::Mode mode) : Input(), m_mode(mode), m_buffer(new QBuffer) { m_buffer->setData(dataFromClipboard(mode)); if (!m_buffer->open(QIODevice::ReadOnly)) throw Exception(gpg_error(GPG_ERR_EIO), i18n("Could not open clipboard for reading")); } void ClipboardInput::setLabel(const QString &) { notImplemented(); } QString ClipboardInput::label() const { switch (m_mode) { case QClipboard::Clipboard: return i18n("Clipboard contents"); case QClipboard::FindBuffer: return i18n("FindBuffer contents"); case QClipboard::Selection: return i18n("Current selection"); }; return QString(); } unsigned int ClipboardInput::classification() const { return classifyContent(m_buffer->data()); } #endif // QT_NO_CLIPBOARD Input::~Input() {} void Input::finalize() { if (const std::shared_ptr io = ioDevice()) if (io->isOpen()) { qCDebug(KLEOPATRA_LOG) << "closing input"; io->close(); } } diff --git a/src/utils/kdpipeiodevice.cpp b/src/utils/kdpipeiodevice.cpp index b36204b1f..926ee3740 100644 --- a/src/utils/kdpipeiodevice.cpp +++ b/src/utils/kdpipeiodevice.cpp @@ -1,1035 +1,1035 @@ /* SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB SPDX-License-Identifier: LGPL-2.0-or-later */ #include #include "kdpipeiodevice.h" #include #include #include #include #include #include "kleopatra_debug.h" #include #include #include #ifdef Q_OS_WIN32 # ifndef NOMINMAX # define NOMINMAX # endif # include # include #else # include # include #endif #ifndef KDAB_CHECK_THIS # define KDAB_CHECK_CTOR (void)1 # define KDAB_CHECK_DTOR KDAB_CHECK_CTOR # define KDAB_CHECK_THIS KDAB_CHECK_CTOR #endif #define LOCKED( d ) const QMutexLocker locker( &d->mutex ) #define synchronized( d ) if ( int i = 0 ) {} else for ( const QMutexLocker locker( &d->mutex ) ; !i ; ++i ) const unsigned int BUFFER_SIZE = 4096; const bool ALLOW_QIODEVICE_BUFFERING = true; namespace { KDPipeIODevice::DebugLevel s_debugLevel = KDPipeIODevice::NoDebug; } #define QDebug if( s_debugLevel == KDPipeIODevice::NoDebug ){}else qDebug namespace { class Reader : public QThread { Q_OBJECT public: Reader(int fd, Qt::HANDLE handle); ~Reader() override; qint64 readData(char *data, qint64 maxSize); unsigned int bytesInBuffer() const { return (wptr + sizeof buffer - rptr) % sizeof buffer; } bool bufferFull() const { return bytesInBuffer() == sizeof buffer - 1; } bool bufferEmpty() const { return bytesInBuffer() == 0; } bool bufferContains(char ch) { const unsigned int bib = bytesInBuffer(); for (unsigned int i = rptr; i < rptr + bib; ++i) if (buffer[i % sizeof buffer] == ch) { return true; } return false; } void notifyReadyRead(); Q_SIGNALS: void readyRead(); protected: void run() override; private: int fd; Qt::HANDLE handle; public: QMutex mutex; QWaitCondition waitForCancelCondition; QWaitCondition bufferNotFullCondition; QWaitCondition bufferNotEmptyCondition; QWaitCondition hasStarted; QWaitCondition readyReadSentCondition; QWaitCondition blockedConsumerIsDoneCondition; bool cancel; bool eof; bool error; bool eofShortCut; int errorCode; bool isReading; bool consumerBlocksOnUs; private: unsigned int rptr, wptr; char buffer[BUFFER_SIZE + 1]; // need to keep one byte free to detect empty state }; Reader::Reader(int fd_, Qt::HANDLE handle_) : QThread(), fd(fd_), handle(handle_), mutex(), bufferNotFullCondition(), bufferNotEmptyCondition(), hasStarted(), cancel(false), eof(false), error(false), eofShortCut(false), errorCode(0), isReading(false), consumerBlocksOnUs(false), rptr(0), wptr(0) { } Reader::~Reader() {} class Writer : public QThread { Q_OBJECT public: Writer(int fd, Qt::HANDLE handle); ~Writer() override; qint64 writeData(const char *data, qint64 size); unsigned int bytesInBuffer() const { return numBytesInBuffer; } bool bufferFull() const { return numBytesInBuffer == sizeof buffer; } bool bufferEmpty() const { return numBytesInBuffer == 0; } Q_SIGNALS: void bytesWritten(qint64); protected: void run() override; private: int fd; Qt::HANDLE handle; public: QMutex mutex; QWaitCondition bufferEmptyCondition; QWaitCondition bufferNotEmptyCondition; QWaitCondition hasStarted; bool cancel; bool error; int errorCode; private: unsigned int numBytesInBuffer; char buffer[BUFFER_SIZE]; }; } Writer::Writer(int fd_, Qt::HANDLE handle_) : QThread(), fd(fd_), handle(handle_), mutex(), bufferEmptyCondition(), bufferNotEmptyCondition(), hasStarted(), cancel(false), error(false), errorCode(0), numBytesInBuffer(0) { } Writer::~Writer() {} class KDPipeIODevice::Private : public QObject { Q_OBJECT friend class ::KDPipeIODevice; KDPipeIODevice *const q; public: explicit Private(KDPipeIODevice *qq); - ~Private(); + ~Private() override; bool doOpen(int, Qt::HANDLE, OpenMode); bool startReaderThread(); bool startWriterThread(); void stopThreads(); public Q_SLOTS: void emitReadyRead(); private: int fd; Qt::HANDLE handle; Reader *reader; Writer *writer; bool triedToStartReader; bool triedToStartWriter; }; KDPipeIODevice::DebugLevel KDPipeIODevice::debugLevel() { return s_debugLevel; } void KDPipeIODevice::setDebugLevel(KDPipeIODevice::DebugLevel level) { s_debugLevel = level; } KDPipeIODevice::Private::Private(KDPipeIODevice *qq) : QObject(qq), q(qq), fd(-1), handle(nullptr), reader(nullptr), writer(nullptr), triedToStartReader(false), triedToStartWriter(false) { } KDPipeIODevice::Private::~Private() { QDebug("KDPipeIODevice::~Private(): Destroying %p", (void *) q); } KDPipeIODevice::KDPipeIODevice(QObject *p) : QIODevice(p), d(new Private(this)) { KDAB_CHECK_CTOR; } KDPipeIODevice::KDPipeIODevice(int fd, OpenMode mode, QObject *p) : QIODevice(p), d(new Private(this)) { KDAB_CHECK_CTOR; open(fd, mode); } KDPipeIODevice::KDPipeIODevice(Qt::HANDLE handle, OpenMode mode, QObject *p) : QIODevice(p), d(new Private(this)) { KDAB_CHECK_CTOR; open(handle, mode); } KDPipeIODevice::~KDPipeIODevice() { KDAB_CHECK_DTOR; if (isOpen()) { close(); } delete d; d = nullptr; } bool KDPipeIODevice::open(int fd, OpenMode mode) { KDAB_CHECK_THIS; #ifdef Q_OS_WIN32 return d->doOpen(fd, (HANDLE)_get_osfhandle(fd), mode); #else return d->doOpen(fd, nullptr, mode); #endif } bool KDPipeIODevice::open(Qt::HANDLE h, OpenMode mode) { KDAB_CHECK_THIS; #ifdef Q_OS_WIN32 return d->doOpen(-1, h, mode); #else Q_UNUSED(h) Q_UNUSED(mode) Q_ASSERT(!"KDPipeIODevice::open( Qt::HANDLE, OpenMode ) should never be called except on Windows."); return false; #endif } bool KDPipeIODevice::Private::startReaderThread() { if (triedToStartReader) { return true; } triedToStartReader = true; if (reader && !reader->isRunning() && !reader->isFinished()) { QDebug("KDPipeIODevice::Private::startReaderThread(): locking reader (CONSUMER THREAD)"); LOCKED(reader); QDebug("KDPipeIODevice::Private::startReaderThread(): locked reader (CONSUMER THREAD)"); reader->start(QThread::HighestPriority); QDebug("KDPipeIODevice::Private::startReaderThread(): waiting for hasStarted (CONSUMER THREAD)"); const bool hasStarted = reader->hasStarted.wait(&reader->mutex, 1000); QDebug("KDPipeIODevice::Private::startReaderThread(): returned from hasStarted (CONSUMER THREAD)"); return hasStarted; } return true; } bool KDPipeIODevice::Private::startWriterThread() { if (triedToStartWriter) { return true; } triedToStartWriter = true; if (writer && !writer->isRunning() && !writer->isFinished()) { LOCKED(writer); writer->start(QThread::HighestPriority); if (!writer->hasStarted.wait(&writer->mutex, 1000)) { return false; } } return true; } void KDPipeIODevice::Private::emitReadyRead() { QPointer thisPointer(this); QDebug("KDPipeIODevice::Private::emitReadyRead %p", (void *) this); Q_EMIT q->readyRead(); if (!thisPointer) { return; } if (reader) { QDebug("KDPipeIODevice::Private::emitReadyRead %p: locking reader (CONSUMER THREAD)", ( void *) this); synchronized(reader) { QDebug("KDPipeIODevice::Private::emitReadyRead %p: locked reader (CONSUMER THREAD)", ( void *) this); reader->readyReadSentCondition.wakeAll(); QDebug("KDPipeIODevice::Private::emitReadyRead %p: buffer empty: %d reader in ReadFile: %d", (void *)this, reader->bufferEmpty(), reader->isReading); } } QDebug("KDPipeIODevice::Private::emitReadyRead %p leaving", (void *) this); } bool KDPipeIODevice::Private::doOpen(int fd_, Qt::HANDLE handle_, OpenMode mode_) { if (q->isOpen()) { return false; } #ifdef Q_OS_WIN32 if (!handle_) { return false; } #else if (fd_ < 0) { return false; } #endif if (!(mode_ & ReadWrite)) { return false; // need to have at least read -or- write } std::unique_ptr reader_; std::unique_ptr writer_; if (mode_ & ReadOnly) { reader_ = std::make_unique(fd_, handle_); QDebug("KDPipeIODevice::doOpen (%p): created reader (%p) for fd %d", (void *)this, (void *)reader_.get(), fd_); connect(reader_.get(), &Reader::readyRead, this, &Private::emitReadyRead, Qt::QueuedConnection); } if (mode_ & WriteOnly) { writer_ = std::make_unique(fd_, handle_); QDebug("KDPipeIODevice::doOpen (%p): created writer (%p) for fd %d", (void *)this, (void *)writer_.get(), fd_); connect(writer_.get(), &Writer::bytesWritten, q, &QIODevice::bytesWritten, Qt::QueuedConnection); } // commit to *this: fd = fd_; handle = handle_; reader = reader_.release(); writer = writer_.release(); q->setOpenMode(mode_ | Unbuffered); return true; } int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS; return d->fd; } Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS; return d->handle; } qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS; const qint64 base = QIODevice::bytesAvailable(); if (!d->triedToStartReader) { d->startReaderThread(); return base; } if (d->reader) { synchronized(d->reader) { const qint64 inBuffer = d->reader->bytesInBuffer(); return base + inBuffer; } } return base; } qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; d->startWriterThread(); const qint64 base = QIODevice::bytesToWrite(); if (d->writer) { synchronized(d->writer) return base + d->writer->bytesInBuffer(); } return base; } bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS; d->startReaderThread(); if (QIODevice::canReadLine()) { return true; } if (d->reader) { synchronized(d->reader) return d->reader->bufferContains('\n'); } return true; } bool KDPipeIODevice::isSequential() const { return true; } bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS; d->startReaderThread(); if (!QIODevice::atEnd()) { QDebug("%p: KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", (void *)this, static_cast(bytesAvailable())); return false; } if (!isOpen()) { return true; } if (d->reader->eofShortCut) { return true; } LOCKED(d->reader); const bool eof = (d->reader->error || d->reader->eof) && d->reader->bufferEmpty(); if (!eof) { if (!d->reader->error && !d->reader->eof) { QDebug("%p: KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof", (void *)(this)); } if (!d->reader->bufferEmpty()) { QDebug("%p: KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()", (void *) this); } } return eof; } bool KDPipeIODevice::waitForBytesWritten(int msecs) { KDAB_CHECK_THIS; d->startWriterThread(); Writer *const w = d->writer; if (!w) { return true; } LOCKED(w); QDebug("KDPipeIODevice::waitForBytesWritten (%p,w=%p): entered locked area", (void *)this, (void *) w); return w->bufferEmpty() || w->error || w->bufferEmptyCondition.wait(&w->mutex, msecs); } bool KDPipeIODevice::waitForReadyRead(int msecs) { KDAB_CHECK_THIS; QDebug("KDPipeIODEvice::waitForReadyRead()(%p)", (void *) this); d->startReaderThread(); if (ALLOW_QIODEVICE_BUFFERING) { if (bytesAvailable() > 0) { return true; } } Reader *const r = d->reader; if (!r || r->eofShortCut) { return true; } LOCKED(r); if (r->bytesInBuffer() != 0 || r->eof || r->error) { return true; } Q_ASSERT(false); // ### wtf? return r->bufferNotEmptyCondition.wait(&r->mutex, msecs); } template class TemporaryValue { public: TemporaryValue(T &var_, const T &tv) : var(var_), oldValue(var_) { var = tv; } ~TemporaryValue() { var = oldValue; } private: T &var; const T oldValue; }; bool KDPipeIODevice::readWouldBlock() const { d->startReaderThread(); LOCKED(d->reader); return d->reader->bufferEmpty() && !d->reader->eof && !d->reader->error; } bool KDPipeIODevice::writeWouldBlock() const { d->startWriterThread(); LOCKED(d->writer); return !d->writer->bufferEmpty() && !d->writer->error; } qint64 KDPipeIODevice::readData(char *data, qint64 maxSize) { KDAB_CHECK_THIS; QDebug("%p: KDPipeIODevice::readData: data=%s, maxSize=%lld", (void *)this, data, maxSize); d->startReaderThread(); Reader *const r = d->reader; Q_ASSERT(r); //assert( r->isRunning() ); // wrong (might be eof, error) Q_ASSERT(data || maxSize == 0); Q_ASSERT(maxSize >= 0); if (r->eofShortCut) { QDebug("%p: KDPipeIODevice::readData: hit eofShortCut, returning 0", (void *)this); return 0; } if (maxSize < 0) { maxSize = 0; } if (ALLOW_QIODEVICE_BUFFERING) { if (bytesAvailable() > 0) { maxSize = std::min(maxSize, bytesAvailable()); // don't block } } QDebug("%p: KDPipeIODevice::readData: try to lock reader (CONSUMER THREAD)", (void *) this); LOCKED(r); QDebug("%p: KDPipeIODevice::readData: locked reader (CONSUMER THREAD)", (void *) this); r->readyReadSentCondition.wakeAll(); if (/* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof) { // ### block on maxSize == 0? QDebug("%p: KDPipeIODevice::readData: waiting for bufferNotEmptyCondition (CONSUMER THREAD)", (void *) this); const TemporaryValue tmp(d->reader->consumerBlocksOnUs, true); r->bufferNotEmptyCondition.wait(&r->mutex); r->blockedConsumerIsDoneCondition.wakeAll(); QDebug("%p: KDPipeIODevice::readData: woke up from bufferNotEmptyCondition (CONSUMER THREAD)", (void *) this); } if (r->bufferEmpty()) { QDebug("%p: KDPipeIODevice::readData: got empty buffer, signal eof", (void *) this); // woken with an empty buffer must mean either EOF or error: Q_ASSERT(r->eof || r->error); r->eofShortCut = true; return r->eof ? 0 : -1; } QDebug("%p: KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", (void *)this, maxSize); const qint64 bytesRead = r->readData(data, maxSize); QDebug("%p: KDPipeIODevice::readData: read %lld bytes", (void *)this, bytesRead); QDebug("%p (fd=%d): KDPipeIODevice::readData: %s", (void *)this, d->fd, data); return bytesRead; } qint64 Reader::readData(char *data, qint64 maxSize) { qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr; if (numRead > maxSize) { numRead = maxSize; } QDebug("%p: KDPipeIODevice::readData: data=%s, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", (void *)this, data, maxSize, rptr, wptr, bytesInBuffer(), numRead); memcpy(data, buffer + rptr, numRead); rptr = (rptr + numRead) % sizeof buffer; if (!bufferFull()) { QDebug("%p: KDPipeIODevice::readData: signal bufferNotFullCondition", (void *) this); bufferNotFullCondition.wakeAll(); } return numRead; } qint64 KDPipeIODevice::writeData(const char *data, qint64 size) { KDAB_CHECK_THIS; d->startWriterThread(); Writer *const w = d->writer; Q_ASSERT(w); Q_ASSERT(w->error || w->isRunning()); Q_ASSERT(data || size == 0); Q_ASSERT(size >= 0); LOCKED(w); while (!w->error && !w->bufferEmpty()) { QDebug("%p: KDPipeIODevice::writeData: wait for empty buffer", (void *) this); w->bufferEmptyCondition.wait(&w->mutex); QDebug("%p: KDPipeIODevice::writeData: empty buffer signaled", (void *) this); } if (w->error) { return -1; } Q_ASSERT(w->bufferEmpty()); return w->writeData(data, size); } qint64 Writer::writeData(const char *data, qint64 size) { Q_ASSERT(bufferEmpty()); if (size > static_cast(sizeof buffer)) { size = sizeof buffer; } memcpy(buffer, data, size); numBytesInBuffer = size; if (!bufferEmpty()) { bufferNotEmptyCondition.wakeAll(); } return size; } void KDPipeIODevice::Private::stopThreads() { if (triedToStartWriter) { if (writer && q->bytesToWrite() > 0) { q->waitForBytesWritten(-1); } Q_ASSERT(q->bytesToWrite() == 0); } if (Reader *&r = reader) { disconnect(r, &Reader::readyRead, this, &Private::emitReadyRead); synchronized(r) { // tell thread to cancel: r->cancel = true; // and wake it, so it can terminate: r->waitForCancelCondition.wakeAll(); r->bufferNotFullCondition.wakeAll(); r->readyReadSentCondition.wakeAll(); } } if (Writer *&w = writer) { synchronized(w) { // tell thread to cancel: w->cancel = true; // and wake it, so it can terminate: w->bufferNotEmptyCondition.wakeAll(); } } } void KDPipeIODevice::close() { KDAB_CHECK_THIS; QDebug("KDPipeIODevice::close(%p)", (void *) this); if (!isOpen()) { return; } // tell clients we're about to close: Q_EMIT aboutToClose(); d->stopThreads(); #define waitAndDelete( t ) if ( t ) { t->wait(); QThread* const t2 = t; t = nullptr; delete t2; } QDebug("KPipeIODevice::close(%p): wait and closing writer %p", (void *)this, (void *) d->writer); waitAndDelete(d->writer); QDebug("KPipeIODevice::close(%p): wait and closing reader %p", (void *)this, (void *) d->reader); if (d->reader) { LOCKED(d->reader); d->reader->readyReadSentCondition.wakeAll(); } waitAndDelete(d->reader); #undef waitAndDelete #ifdef Q_OS_WIN32 if (d->fd != -1) { _close(d->fd); } else { CloseHandle(d->handle); } #else ::close(d->fd); #endif setOpenMode(NotOpen); d->fd = -1; d->handle = nullptr; } void Reader::run() { LOCKED(this); // too bad QThread doesn't have that itself; a signal isn't enough hasStarted.wakeAll(); QDebug("%p: Reader::run: started", (void *) this); while (true) { if (!cancel && (eof || error)) { //notify the client until the buffer is empty and then once //again so he receives eof/error. After that, wait for him //to cancel const bool wasEmpty = bufferEmpty(); QDebug("%p: Reader::run: received eof(%d) or error(%d), waking everyone", (void *)this, eof, error); notifyReadyRead(); if (!cancel && wasEmpty) { waitForCancelCondition.wait(&mutex); } } else if (!cancel && !bufferFull() && !bufferEmpty()) { QDebug("%p: Reader::run: buffer no longer empty, waking everyone", (void *) this); notifyReadyRead(); } while (!cancel && !error && bufferFull()) { notifyReadyRead(); if (!cancel && bufferFull()) { QDebug("%p: Reader::run: buffer is full, going to sleep", (void *)this); bufferNotFullCondition.wait(&mutex); } } if (cancel) { QDebug("%p: Reader::run: detected cancel", (void *)this); goto leave; } if (!eof && !error) { if (rptr == wptr) { // optimize for larger chunks in case the buffer is empty rptr = wptr = 0; } unsigned int numBytes = (rptr + sizeof buffer - wptr - 1) % sizeof buffer; if (numBytes > sizeof buffer - wptr) { numBytes = sizeof buffer - wptr; } QDebug("%p: Reader::run: rptr=%d, wptr=%d -> numBytes=%d", (void *)this, rptr, wptr, numBytes); Q_ASSERT(numBytes > 0); QDebug("%p: Reader::run: trying to read %d bytes from fd %d", (void *)this, numBytes, fd); #ifdef Q_OS_WIN32 isReading = true; mutex.unlock(); DWORD numRead; const bool ok = ReadFile(handle, buffer + wptr, numBytes, &numRead, 0); mutex.lock(); isReading = false; if (ok) { if (numRead == 0) { QDebug("%p: Reader::run: got eof (numRead==0)", (void *) this); eof = true; } } else { // !ok errorCode = static_cast(GetLastError()); if (errorCode == ERROR_BROKEN_PIPE) { Q_ASSERT(numRead == 0); QDebug("%p: Reader::run: got eof (broken pipe)", (void *) this); eof = true; } else { Q_ASSERT(numRead == 0); QDebug("%p: Reader::run: got error: %s (%d)", (void *) this, strerror(errorCode), errorCode); error = true; } } #else qint64 numRead; mutex.unlock(); do { numRead = ::read(fd, buffer + wptr, numBytes); } while (numRead == -1 && errno == EINTR); mutex.lock(); if (numRead < 0) { errorCode = errno; error = true; QDebug("%p: Reader::run: got error: %d", (void *)this, errorCode); } else if (numRead == 0) { QDebug("%p: Reader::run: eof detected", (void *)this); eof = true; } #endif QDebug("%p (fd=%d): Reader::run: read %ld bytes", (void *) this, fd, static_cast(numRead)); QDebug("%p (fd=%d): Reader::run: %s", (void *)this, fd, buffer); if (numRead > 0) { QDebug("%p: Reader::run: buffer before: rptr=%4d, wptr=%4d", (void *)this, rptr, wptr); wptr = (wptr + numRead) % sizeof buffer; QDebug("%p: Reader::run: buffer after: rptr=%4d, wptr=%4d", (void *)this, rptr, wptr); } } } leave: QDebug("%p: Reader::run: terminated", (void *)this); } void Reader::notifyReadyRead() { QDebug("notifyReadyRead: %d bytes available", bytesInBuffer()); Q_ASSERT(!cancel); if (consumerBlocksOnUs) { bufferNotEmptyCondition.wakeAll(); blockedConsumerIsDoneCondition.wait(&mutex); return; } QDebug("notifyReadyRead: Q_EMIT signal"); Q_EMIT readyRead(); readyReadSentCondition.wait(&mutex); QDebug("notifyReadyRead: returning from waiting, leave"); } void Writer::run() { LOCKED(this); // too bad QThread doesn't have that itself; a signal isn't enough hasStarted.wakeAll(); qCDebug(KLEOPATRA_LOG) << this << "Writer::run: started"; while (true) { while (!cancel && bufferEmpty()) { qCDebug(KLEOPATRA_LOG) << this << "Writer::run: buffer is empty, wake bufferEmptyCond listeners"; bufferEmptyCondition.wakeAll(); Q_EMIT bytesWritten(0); qCDebug(KLEOPATRA_LOG) << this << "Writer::run: buffer is empty, going to sleep"; bufferNotEmptyCondition.wait(&mutex); qCDebug(KLEOPATRA_LOG) << this << "Writer::run: woke up"; } if (cancel) { qCDebug(KLEOPATRA_LOG) << this << "Writer::run: detected cancel"; goto leave; } Q_ASSERT(numBytesInBuffer > 0); qCDebug(KLEOPATRA_LOG) << this << "Writer::run: Trying to write " << numBytesInBuffer << "bytes"; qint64 totalWritten = 0; do { mutex.unlock(); #ifdef Q_OS_WIN32 DWORD numWritten; QDebug("%p (fd=%d): Writer::run: buffer before WriteFile (numBytes=%lld): %s:", (void *) this, fd, numBytesInBuffer, buffer); QDebug("%p (fd=%d): Writer::run: Going into WriteFile", (void *) this, fd); if (!WriteFile(handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0)) { mutex.lock(); errorCode = static_cast(GetLastError()); QDebug("%p: Writer::run: got error code: %d", (void *) this, errorCode); error = true; goto leave; } #else qint64 numWritten; do { numWritten = ::write(fd, buffer + totalWritten, numBytesInBuffer - totalWritten); } while (numWritten == -1 && errno == EINTR); if (numWritten < 0) { mutex.lock(); errorCode = errno; QDebug("%p: Writer::run: got error code: %s (%d)", (void *)this, strerror(errorCode), errorCode); error = true; goto leave; } #endif QDebug("%p (fd=%d): Writer::run: buffer after WriteFile (numBytes=%u): %s:", (void *)this, fd, numBytesInBuffer, buffer); totalWritten += numWritten; mutex.lock(); } while (totalWritten < numBytesInBuffer); qCDebug(KLEOPATRA_LOG) << this << "Writer::run: wrote " << totalWritten << "bytes"; numBytesInBuffer = 0; qCDebug(KLEOPATRA_LOG) << this << "Writer::run: buffer is empty, wake bufferEmptyCond listeners"; bufferEmptyCondition.wakeAll(); Q_EMIT bytesWritten(totalWritten); } leave: qCDebug(KLEOPATRA_LOG) << this << "Writer::run: terminating"; numBytesInBuffer = 0; qCDebug(KLEOPATRA_LOG) << this << "Writer::run: buffer is empty, wake bufferEmptyCond listeners"; bufferEmptyCondition.wakeAll(); Q_EMIT bytesWritten(0); } // static std::pair KDPipeIODevice::makePairOfConnectedPipes() { KDPipeIODevice *read = nullptr; KDPipeIODevice *write = nullptr; #ifdef Q_OS_WIN32 HANDLE rh; HANDLE wh; SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; if (CreatePipe(&rh, &wh, &sa, BUFFER_SIZE)) { read = new KDPipeIODevice; read->open(rh, ReadOnly); write = new KDPipeIODevice; write->open(wh, WriteOnly); } #else int fds[2]; if (pipe(fds) == 0) { read = new KDPipeIODevice; read->open(fds[0], ReadOnly); write = new KDPipeIODevice; write->open(fds[1], WriteOnly); } #endif return std::make_pair(read, write); } #ifdef KDAB_DEFINE_CHECKS KDAB_DEFINE_CHECKS(KDPipeIODevice) { if (!isOpen()) { Q_ASSERT(openMode() == NotOpen); Q_ASSERT(!d->reader); Q_ASSERT(!d->writer); #ifdef Q_OS_WIN32 Q_ASSERT(!d->handle); #else Q_ASSERT(d->fd < 0); #endif } else { Q_ASSERT(openMode() != NotOpen); Q_ASSERT(openMode() & ReadWrite); if (openMode() & ReadOnly) { Q_ASSERT(d->reader); synchronized(d->reader) Q_ASSERT(d->reader->eof || d->reader->error || d->reader->isRunning()); } if (openMode() & WriteOnly) { Q_ASSERT(d->writer); synchronized(d->writer) Q_ASSERT(d->writer->error || d->writer->isRunning()); } #ifdef Q_OS_WIN32 Q_ASSERT(d->handle); #else Q_ASSERT(d->fd >= 0); #endif } } #endif // KDAB_DEFINE_CHECKS #include "kdpipeiodevice.moc" diff --git a/src/utils/kuniqueservice.h b/src/utils/kuniqueservice.h index 9d577292d..54851346e 100644 --- a/src/utils/kuniqueservice.h +++ b/src/utils/kuniqueservice.h @@ -1,68 +1,68 @@ #pragma once /* kuniqueservice.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2016 Bundesamt für Sicherheit in der Informationstechnik SPDX-FileContributor: Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include /** * This class can be used to create a unique service and redirect calls * to this service similarly to KDBusService(KDBusService::Unique). * @code * YourApplication app(argc, argv); * * KUniqueService service; * QObject::connect(&service, &KUniqueService::activateRequested, * &app, &YourApplication::slotActivateRequested); * QObject::connect(&app, &YourApplication::setExitValue, * &service, [&service](int i) { * service.setExitValue(i); * }); * @endcode * This will redirect calls to running instances over the * the slotActivateRequested. When you set the exit * value the calling process will afterwards exit with the * code provided. * If you do not set the exit value the application will not * be terminated. * @author Andre Heinecke (aheinecke@intevation.org) */ class KUniqueService : public QObject { Q_OBJECT public: /** * Default constructor */ KUniqueService(); - ~KUniqueService(); + ~KUniqueService() override; public Q_SLOTS: /** * Set the exit @p code the second app should use to terminate. * If unset it exits with 0. * @param code The exit code. */ void setExitValue(int code); Q_SIGNALS: void activateRequested(const QStringList &arguments, const QString &workingDirectory); private: void emitActivateRequested(const QStringList &arguments, const QString &workingDirectory) { Q_EMIT activateRequested(arguments, workingDirectory); } class KUniqueServicePrivate; Q_DECLARE_PRIVATE(KUniqueService) KUniqueServicePrivate *d_ptr; }; diff --git a/src/utils/output.cpp b/src/utils/output.cpp index 809e42b93..baa1c45c6 100644 --- a/src/utils/output.cpp +++ b/src/utils/output.cpp @@ -1,762 +1,762 @@ /* -*- mode: c++; c-basic-offset:4 -*- utils/output.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 "output.h" #include "input_p.h" #include "detail_p.h" #include "kleo_assert.h" #include "kdpipeiodevice.h" #include "log.h" #include "cached.h" #include #include #include #include "kleopatra_debug.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN # include #endif #include using namespace Kleo; using namespace Kleo::_detail; static const int PROCESS_MAX_RUNTIME_TIMEOUT = -1; // no timeout static const int PROCESS_TERMINATE_TIMEOUT = 5 * 1000; // 5s class OverwritePolicy::Private { public: Private(QWidget *p, OverwritePolicy::Policy pol) : policy(pol), widget(p) {} OverwritePolicy::Policy policy; QWidget *widget; }; OverwritePolicy::OverwritePolicy(QWidget *parent, Policy initialPolicy) : d(new Private(parent, initialPolicy)) { } OverwritePolicy::~OverwritePolicy() {} OverwritePolicy::Policy OverwritePolicy::policy() const { return d->policy; } void OverwritePolicy::setPolicy(Policy policy) { d->policy = policy; } QWidget *OverwritePolicy::parentWidget() const { return d->widget; } namespace { class TemporaryFile : public QTemporaryFile { public: explicit TemporaryFile() : QTemporaryFile() {} explicit TemporaryFile(const QString &templateName) : QTemporaryFile(templateName) {} explicit TemporaryFile(QObject *parent) : QTemporaryFile(parent) {} explicit TemporaryFile(const QString &templateName, QObject *parent) : QTemporaryFile(templateName, parent) {} void close() override { if (isOpen()) { m_oldFileName = fileName(); } QTemporaryFile::close(); } bool openNonInheritable() { if (!QTemporaryFile::open()) { return false; } #if defined(Q_OS_WIN) //QTemporaryFile (tested with 4.3.3) creates the file handle as inheritable. //The handle is then inherited by gpgsm, which prevents deletion of the temp file //in FileOutput::doFinalize() //There are no inheritable handles under wince return SetHandleInformation((HANDLE)_get_osfhandle(handle()), HANDLE_FLAG_INHERIT, 0); #endif return true; } QString oldFileName() const { return m_oldFileName; } private: QString m_oldFileName; }; template struct inhibit_close : T_IODevice { explicit inhibit_close() : T_IODevice() {} template explicit inhibit_close(T1 &t1) : T_IODevice(t1) {} /* reimp */ void close() override {} void reallyClose() { T_IODevice::close(); } }; template struct redirect_close : T_IODevice { explicit redirect_close() : T_IODevice(), m_closed(false) {} template explicit redirect_close(T1 &t1) : T_IODevice(t1), m_closed(false) {} /* reimp */ void close() override { this->closeWriteChannel(); m_closed = true; } bool isClosed() const { return m_closed; } private: bool m_closed; }; class FileOutput; class OutputInput : public InputImplBase { public: OutputInput(const std::shared_ptr &output); unsigned int classification() const override { return 0; } void outputFinalized() { if (!m_ioDevice->open(QIODevice::ReadOnly)) { qCCritical(KLEOPATRA_LOG) << "Failed to open file for reading"; } } std::shared_ptr ioDevice() const override { return m_ioDevice; } unsigned long long size() const override { return 0; } private: std::shared_ptr m_output; mutable std::shared_ptr m_ioDevice = nullptr; }; class OutputImplBase : public Output { public: OutputImplBase() : Output(), m_defaultLabel(), m_customLabel(), m_errorString(), m_isFinalized(false), m_isFinalizing(false), m_cancelPending(false), m_canceled(false), m_binaryOpt(false) { } QString label() const override { return m_customLabel.isEmpty() ? m_defaultLabel : m_customLabel; } void setLabel(const QString &label) override { m_customLabel = label; } void setDefaultLabel(const QString &l) { m_defaultLabel = l; } void setBinaryOpt(bool value) override { m_binaryOpt = value; } bool binaryOpt() const override { return m_binaryOpt; } QString errorString() const override { if (m_errorString.dirty()) { m_errorString = doErrorString(); } return m_errorString; } bool isFinalized() const override { return m_isFinalized; } void finalize() override { qCDebug(KLEOPATRA_LOG) << this; if (m_isFinalized || m_isFinalizing) { return; } m_isFinalizing = true; try { doFinalize(); } catch (...) { m_isFinalizing = false; throw; } m_isFinalizing = false; m_isFinalized = true; if (m_cancelPending) { cancel(); } } void cancel() override { qCDebug(KLEOPATRA_LOG) << this; if (m_isFinalizing) { m_cancelPending = true; } else if (!m_canceled) { m_isFinalizing = true; try { doCancel(); } catch (...) {} m_isFinalizing = false; m_isFinalized = false; m_canceled = true; } } private: virtual QString doErrorString() const { if (std::shared_ptr io = ioDevice()) { return io->errorString(); } else { return i18n("No output device"); } } virtual void doFinalize() = 0; virtual void doCancel() = 0; private: QString m_defaultLabel; QString m_customLabel; mutable cached m_errorString; bool m_isFinalized : 1; bool m_isFinalizing : 1; bool m_cancelPending : 1; bool m_canceled : 1; bool m_binaryOpt : 1; }; class PipeOutput : public OutputImplBase { public: explicit PipeOutput(assuan_fd_t fd); std::shared_ptr ioDevice() const override { return m_io; } void doFinalize() override { m_io->reallyClose(); } void doCancel() override { doFinalize(); } private: std::shared_ptr< inhibit_close > m_io; }; class ProcessStdInOutput : public OutputImplBase { public: explicit ProcessStdInOutput(const QString &cmd, const QStringList &args, const QDir &wd); std::shared_ptr ioDevice() const override { return m_proc; } void doFinalize() override { /* Make sure the data is written in the output here. If this is not done the output will be written in small chunks trough the eventloop causing an unnecessary delay before the process has even a chance to work and finish. This delay is mainly noticeable on Windows where it can take ~30 seconds to write out a 10MB file in the 512 byte chunks gpgme serves. */ qCDebug(KLEOPATRA_LOG) << "Waiting for " << m_proc->bytesToWrite() << " Bytes to be written"; while (m_proc->waitForBytesWritten(PROCESS_MAX_RUNTIME_TIMEOUT)); if (!m_proc->isClosed()) { m_proc->close(); } m_proc->waitForFinished(PROCESS_MAX_RUNTIME_TIMEOUT); } bool failed() const override { if (!m_proc) { return false; } return !(m_proc->exitStatus() == QProcess::NormalExit && m_proc->exitCode() == 0); } void doCancel() override { m_proc->terminate(); QTimer::singleShot(PROCESS_TERMINATE_TIMEOUT, m_proc.get(), &QProcess::kill); } QString label() const override; private: QString doErrorString() const override; private: const QString m_command; const QStringList m_arguments; const std::shared_ptr< redirect_close > m_proc; }; class FileOutput : public OutputImplBase { public: explicit FileOutput(const QString &fileName, const std::shared_ptr &policy); - ~FileOutput() + ~FileOutput() override { qCDebug(KLEOPATRA_LOG) << this; } QString label() const override { return QFileInfo(m_fileName).fileName(); } std::shared_ptr ioDevice() const override { return m_tmpFile; } void doFinalize() override; void doCancel() override { qCDebug(KLEOPATRA_LOG) << this; } QString fileName() const { return m_fileName; } void attachInput(const std::shared_ptr &input) { m_attachedInput = std::weak_ptr(input); } private: bool obtainOverwritePermission(); private: const QString m_fileName; std::shared_ptr< TemporaryFile > m_tmpFile; const std::shared_ptr m_policy; std::weak_ptr m_attachedInput; }; #ifndef QT_NO_CLIPBOARD class ClipboardOutput : public OutputImplBase { public: explicit ClipboardOutput(QClipboard::Mode mode); QString label() const override; std::shared_ptr ioDevice() const override { return m_buffer; } void doFinalize() override; void doCancel() override {} private: QString doErrorString() const override { return QString(); } private: const QClipboard::Mode m_mode; std::shared_ptr m_buffer; }; #endif // QT_NO_CLIPBOARD class ByteArrayOutput: public OutputImplBase { public: explicit ByteArrayOutput(QByteArray *data): m_buffer(std::shared_ptr(new QBuffer(data))) { if (!m_buffer->open(QIODevice::WriteOnly)) throw Exception(gpg_error(GPG_ERR_EIO), QStringLiteral("Could not open bytearray for writing?!")); } QString label() const override { return m_label; } void setLabel(const QString &label) override { m_label = label; } std::shared_ptr ioDevice() const override { return m_buffer; } void doFinalize() override { m_buffer->close(); } void doCancel() override { m_buffer->close(); } private: QString doErrorString() const override { return QString(); } private: QString m_label; std::shared_ptr m_buffer; }; } std::shared_ptr Output::createFromPipeDevice(assuan_fd_t fd, const QString &label) { std::shared_ptr po(new PipeOutput(fd)); po->setDefaultLabel(label); return po; } PipeOutput::PipeOutput(assuan_fd_t fd) : OutputImplBase(), m_io(new inhibit_close) { errno = 0; if (!m_io->open(fd, QIODevice::WriteOnly)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not open FD %1 for writing", assuanFD2int(fd))); } std::shared_ptr Output::createFromFile(const QString &fileName, bool forceOverwrite) { return createFromFile(fileName, std::shared_ptr(new OverwritePolicy(nullptr, forceOverwrite ? OverwritePolicy::Allow : OverwritePolicy::Deny))); } std::shared_ptr Output::createFromFile(const QString &fileName, const std::shared_ptr &policy) { std::shared_ptr fo(new FileOutput(fileName, policy)); qCDebug(KLEOPATRA_LOG) << fo.get(); return fo; } FileOutput::FileOutput(const QString &fileName, const std::shared_ptr &policy) : OutputImplBase(), m_fileName(fileName), m_tmpFile(new TemporaryFile(fileName)), m_policy(policy) { Q_ASSERT(m_policy); errno = 0; if (!m_tmpFile->openNonInheritable()) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not create temporary file for output \"%1\"", fileName)); } bool FileOutput::obtainOverwritePermission() { if (m_policy->policy() != OverwritePolicy::Ask) { return m_policy->policy() == OverwritePolicy::Allow; } const int sel = KMessageBox::questionYesNoCancel(m_policy->parentWidget(), i18n("The file %1 already exists.\n" "Overwrite?", m_fileName), i18n("Overwrite Existing File?"), KStandardGuiItem::overwrite(), KGuiItem(i18n("Overwrite All")), KStandardGuiItem::cancel()); if (sel == KMessageBox::No) { //Overwrite All m_policy->setPolicy(OverwritePolicy::Allow); } return sel == KMessageBox::Yes || sel == KMessageBox::No; } void FileOutput::doFinalize() { qCDebug(KLEOPATRA_LOG) << this; struct Remover { QString file; ~Remover() { if (QFile::exists(file)) { QFile::remove(file); } } } remover; kleo_assert(m_tmpFile); if (m_tmpFile->isOpen()) { m_tmpFile->close(); } QString tmpFileName = remover.file = m_tmpFile->oldFileName(); m_tmpFile->setAutoRemove(false); QPointer guard = m_tmpFile.get(); m_tmpFile.reset(); // really close the file - needed on Windows for renaming :/ kleo_assert(!guard); // if this triggers, we need to audit for holder of std::shared_ptrs. const QFileInfo fi(tmpFileName); bool qtbug83365_workaround = false; if (!fi.exists()) { /* QT Bug 83365 since qt 5.13 causes the filename of temporary files * in UNC path name directories (unmounted samba shares) to start with * UNC/ instead of the // that Qt can actually handle for things like * rename and remove. So if we can't find our temporary file we try * to workaround that bug. */ qCDebug(KLEOPATRA_LOG) << "failure to find " << tmpFileName; if (tmpFileName.startsWith(QStringLiteral("UNC"))) { tmpFileName.replace(QRegExp(QStringLiteral("^UNC")), QStringLiteral("/")); qtbug83365_workaround = true; } const QFileInfo fi2(tmpFileName); if (!fi2.exists()) { throw Exception(gpg_error(GPG_ERR_EIO), QStringLiteral("Could not find temporary file \"%1\".").arg(tmpFileName)); } } qCDebug(KLEOPATRA_LOG) << this << " renaming " << tmpFileName << "->" << m_fileName; if (QFile::rename(tmpFileName, m_fileName)) { qCDebug(KLEOPATRA_LOG) << this << "succeeded"; if (!m_attachedInput.expired()) { m_attachedInput.lock()->outputFinalized(); } return; } qCDebug(KLEOPATRA_LOG) << this << "failed"; if (!obtainOverwritePermission()) throw Exception(gpg_error(GPG_ERR_CANCELED), i18n("Overwriting declined")); qCDebug(KLEOPATRA_LOG) << this << "going to overwrite" << m_fileName; if (!QFile::remove(m_fileName)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not remove file \"%1\" for overwriting.", m_fileName)); qCDebug(KLEOPATRA_LOG) << this << "succeeded, renaming " << tmpFileName << "->" << m_fileName; if (QFile::rename(tmpFileName, m_fileName)) { qCDebug(KLEOPATRA_LOG) << this << "succeeded"; if (!m_attachedInput.expired()) { m_attachedInput.lock()->outputFinalized(); } if (qtbug83365_workaround) { QFile::remove(tmpFileName); } return; } qCDebug(KLEOPATRA_LOG) << this << "failed"; throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n(R"(Could not rename file "%1" to "%2")", tmpFileName, m_fileName)); } std::shared_ptr Output::createFromProcessStdIn(const QString &command) { return std::shared_ptr(new ProcessStdInOutput(command, QStringList(), QDir::current())); } std::shared_ptr Output::createFromProcessStdIn(const QString &command, const QStringList &args) { return std::shared_ptr(new ProcessStdInOutput(command, args, QDir::current())); } std::shared_ptr Output::createFromProcessStdIn(const QString &command, const QStringList &args, const QDir &wd) { return std::shared_ptr(new ProcessStdInOutput(command, args, wd)); } ProcessStdInOutput::ProcessStdInOutput(const QString &cmd, const QStringList &args, const QDir &wd) : OutputImplBase(), m_command(cmd), m_arguments(args), m_proc(new redirect_close) { qCDebug(KLEOPATRA_LOG) << "cd" << wd.absolutePath() << '\n' << cmd << args; if (cmd.isEmpty()) throw Exception(gpg_error(GPG_ERR_INV_ARG), i18n("Command not specified")); m_proc->setWorkingDirectory(wd.absolutePath()); m_proc->start(cmd, args); m_proc->setReadChannel(QProcess::StandardError); if (!m_proc->waitForStarted()) throw Exception(gpg_error(GPG_ERR_EIO), i18n("Could not start %1 process: %2", cmd, m_proc->errorString())); } QString ProcessStdInOutput::label() const { if (!m_proc) { return OutputImplBase::label(); } // output max. 3 arguments const QString cmdline = (QStringList(m_command) + m_arguments.mid(0, 3)).join(QLatin1Char(' ')); if (m_arguments.size() > 3) { return i18nc("e.g. \"Input to tar xf - file1 ...\"", "Input to %1 ...", cmdline); } else { return i18nc("e.g. \"Input to tar xf - file\"", "Input to %1", cmdline); } } QString ProcessStdInOutput::doErrorString() const { kleo_assert(m_proc); if (m_proc->exitStatus() == QProcess::NormalExit && m_proc->exitCode() == 0) { return QString(); } if (m_proc->error() == QProcess::UnknownError) return i18n("Error while running %1: %2", m_command, QString::fromLocal8Bit(m_proc->readAllStandardError().trimmed().constData())); else { return i18n("Failed to execute %1: %2", m_command, m_proc->errorString()); } } #ifndef QT_NO_CLIPBOARD std::shared_ptr Output::createFromClipboard() { return std::shared_ptr(new ClipboardOutput(QClipboard::Clipboard)); } ClipboardOutput::ClipboardOutput(QClipboard::Mode mode) : OutputImplBase(), m_mode(mode), m_buffer(new QBuffer) { errno = 0; if (!m_buffer->open(QIODevice::WriteOnly)) throw Exception(errno ? gpg_error_from_errno(errno) : gpg_error(GPG_ERR_EIO), i18n("Could not write to clipboard")); } QString ClipboardOutput::label() const { switch (m_mode) { case QClipboard::Clipboard: return i18n("Clipboard"); case QClipboard::FindBuffer: return i18n("Find buffer"); case QClipboard::Selection: return i18n("Selection"); } return QString(); } void ClipboardOutput::doFinalize() { if (m_buffer->isOpen()) { m_buffer->close(); } if (QClipboard *const cb = QApplication::clipboard()) { cb->setText(QString::fromUtf8(m_buffer->data())); } else throw Exception(gpg_error(GPG_ERR_EIO), i18n("Could not find clipboard")); } #endif // QT_NO_CLIPBOARD Output::~Output() {} OutputInput::OutputInput(const std::shared_ptr &output) : m_output(output) , m_ioDevice(new QFile(output->fileName())) { } std::shared_ptr Input::createFromOutput(const std::shared_ptr &output) { if (auto fo = std::dynamic_pointer_cast(output)) { auto input = std::shared_ptr(new OutputInput(fo)); fo->attachInput(input); return input; } else { return {}; } } std::shared_ptr Output::createFromByteArray(QByteArray *data, const QString &label) { auto ret = std::shared_ptr(new ByteArrayOutput(data)); ret->setLabel(label); return ret; } diff --git a/src/utils/writecertassuantransaction.h b/src/utils/writecertassuantransaction.h index 7b6274d77..1423e0320 100644 --- a/src/utils/writecertassuantransaction.h +++ b/src/utils/writecertassuantransaction.h @@ -1,33 +1,33 @@ /* utils/writecertassuantransaction.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include class QByteArray; namespace Kleo { class WriteCertAssuanTransaction: public GpgME::DefaultAssuanTransaction { public: explicit WriteCertAssuanTransaction(const QByteArray &certificateData); - ~WriteCertAssuanTransaction(); + ~WriteCertAssuanTransaction() override; private: GpgME::Data inquire(const char *name, const char *args, GpgME::Error &err) override; private: GpgME::Data mCertData; }; } // namespace Kleo diff --git a/src/view/keylistcontroller.h b/src/view/keylistcontroller.h index babb4fa26..7c8b7b5a1 100644 --- a/src/view/keylistcontroller.h +++ b/src/view/keylistcontroller.h @@ -1,113 +1,113 @@ /* -*- mode: c++; c-basic-offset:4 -*- controllers/keylistcontroller.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 class QAbstractItemView; class QAction; class QPoint; class QItemSelectionModel; class KActionCollection; namespace Kleo { class AbstractKeyListModel; class Command; class TabWidget; class KeyListController : public QObject { Q_OBJECT public: explicit KeyListController(QObject *parent = nullptr); - ~KeyListController(); + ~KeyListController() override; std::vector views() const; void setFlatModel(AbstractKeyListModel *model); AbstractKeyListModel *flatModel() const; void setHierarchicalModel(AbstractKeyListModel *model); AbstractKeyListModel *hierarchicalModel() const; void setParentWidget(QWidget *parent); QWidget *parentWidget() const; QAbstractItemView *currentView() const; void setTabWidget(TabWidget *tabs); TabWidget *tabWidget() const; void registerCommand(Command *cmd); void createActions(KActionCollection *collection); template void registerActionForCommand(QAction *action) { this->registerAction(action, T_Command::restrictions(), &KeyListController::template create); } void enableDisableActions(const QItemSelectionModel *sm) const; bool hasRunningCommands() const; bool shutdownWarningRequired() const; private: void registerAction(QAction *action, Command::Restrictions restrictions, Command * (*create)(QAbstractItemView *, KeyListController *)); template static Command *create(QAbstractItemView *v, KeyListController *c) { return new T_Command(v, c); } public Q_SLOTS: void addView(QAbstractItemView *view); void removeView(QAbstractItemView *view); void setCurrentView(QAbstractItemView *view); void cancelCommands(); void updateConfig(); Q_SIGNALS: void progress(int current, int total); void message(const QString &msg, int timeout = 0); void commandsExecuting(bool); void contextMenuRequested(QAbstractItemView *view, const QPoint &p); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotDestroyed(QObject *)) Q_PRIVATE_SLOT(d, void slotDoubleClicked(QModelIndex)) Q_PRIVATE_SLOT(d, void slotActivated(QModelIndex)) Q_PRIVATE_SLOT(d, void slotSelectionChanged(QItemSelection, QItemSelection)) Q_PRIVATE_SLOT(d, void slotContextMenu(QPoint)) Q_PRIVATE_SLOT(d, void slotCommandFinished()) Q_PRIVATE_SLOT(d, void slotAddKey(GpgME::Key)) Q_PRIVATE_SLOT(d, void slotAboutToRemoveKey(GpgME::Key)) Q_PRIVATE_SLOT(d, void slotProgress(QString, int, int)) Q_PRIVATE_SLOT(d, void slotActionTriggered()) Q_PRIVATE_SLOT(d, void slotCurrentViewChanged(QAbstractItemView *)) }; } diff --git a/src/view/keytreeview.h b/src/view/keytreeview.h index 54c315ce9..f632cf6f0 100644 --- a/src/view/keytreeview.h +++ b/src/view/keytreeview.h @@ -1,158 +1,158 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/keytreeview.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2009 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include #include #include #include class QTreeView; namespace Kleo { class KeyFilter; class AbstractKeyListModel; class AbstractKeyListSortFilterProxyModel; class KeyListSortFilterProxyModel; class KeyTreeView : public QWidget { Q_OBJECT public: explicit KeyTreeView(QWidget *parent = nullptr); KeyTreeView(const QString &stringFilter, const std::shared_ptr &keyFilter, AbstractKeyListSortFilterProxyModel *additionalProxy, QWidget *parent, const KConfigGroup &group); - ~KeyTreeView(); + ~KeyTreeView() override; QTreeView *view() const { return m_view; } AbstractKeyListModel *model() const { return m_isHierarchical ? hierarchicalModel() : flatModel(); } AbstractKeyListModel *flatModel() const { return m_flatModel; } AbstractKeyListModel *hierarchicalModel() const { return m_hierarchicalModel; } void setFlatModel(AbstractKeyListModel *model); void setHierarchicalModel(AbstractKeyListModel *model); void setKeys(const std::vector &keys); const std::vector &keys() const { return m_keys; } void selectKeys(const std::vector &keys); std::vector selectedKeys() const; void addKeysUnselected(const std::vector &keys); void addKeysSelected(const std::vector &keys); void removeKeys(const std::vector &keys); #if 0 void setToolTipOptions(int options); int toolTipOptions() const; #endif QString stringFilter() const { return m_stringFilter; } const std::shared_ptr &keyFilter() const { return m_keyFilter; } bool isHierarchicalView() const { return m_isHierarchical; } void setColumnSizes(const std::vector &sizes); std::vector columnSizes() const; void setSortColumn(int sortColumn, Qt::SortOrder sortOrder); int sortColumn() const; Qt::SortOrder sortOrder() const; virtual KeyTreeView *clone() const { return new KeyTreeView(*this); } void disconnectSearchBar(const QObject *bar); bool connectSearchBar(const QObject *bar); void resizeColumns(); void saveLayout(KConfigGroup &group); void restoreLayout(const KConfigGroup &group); public Q_SLOTS: virtual void setStringFilter(const QString &text); virtual void setKeyFilter(const std::shared_ptr &filter); virtual void setHierarchicalView(bool on); Q_SIGNALS: void stringFilterChanged(const QString &filter); void keyFilterChanged(const std::shared_ptr &filter); void hierarchicalChanged(bool on); protected: KeyTreeView(const KeyTreeView &); private: void init(); void addKeysImpl(const std::vector &, bool); void restoreExpandState(); void setUpTagKeys(); private: std::vector m_keys; KeyListSortFilterProxyModel *m_proxy; AbstractKeyListSortFilterProxyModel *m_additionalProxy; QTreeView *m_view; AbstractKeyListModel *m_flatModel; AbstractKeyListModel *m_hierarchicalModel; QString m_stringFilter; std::shared_ptr m_keyFilter; QStringList m_expandedKeys; KConfigGroup m_group; bool m_isHierarchical : 1; bool m_onceResized : 1; }; } diff --git a/src/view/netkeywidget.h b/src/view/netkeywidget.h index 802f72ca3..0eb9e9575 100644 --- a/src/view/netkeywidget.h +++ b/src/view/netkeywidget.h @@ -1,59 +1,59 @@ /* view/netkeywidget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include class QLabel; class QPushButton; class QScrollArea; namespace Kleo { class NullPinWidget; class KeyTreeView; namespace SmartCard { class NetKeyCard; } // namespace SmartCard class NetKeyWidget: public QWidget { Q_OBJECT public: explicit NetKeyWidget(QWidget *parent = nullptr); - ~NetKeyWidget(); + ~NetKeyWidget() override; void setCard(const SmartCard::NetKeyCard *card); private: void doChangePin(const std::string &keyRef); void createKeyFromCardKeys(); void createCSR(); private: std::string mSerialNumber; QLabel *mSerialNumberLabel = nullptr, *mVersionLabel = nullptr, *mLearnKeysLabel = nullptr, *mErrorLabel = nullptr; NullPinWidget *mNullPinWidget = nullptr; QPushButton *mLearnKeysBtn = nullptr, *mKeyForCardKeysButton = nullptr, *mCreateCSRButton = nullptr, *mChangeNKSPINBtn = nullptr, *mChangeSigGPINBtn = nullptr; KeyTreeView *mTreeView = nullptr; QScrollArea *mArea = nullptr; }; } // namespace Kleo diff --git a/src/view/pivcardwidget.h b/src/view/pivcardwidget.h index 815d620b8..736f35883 100644 --- a/src/view/pivcardwidget.h +++ b/src/view/pivcardwidget.h @@ -1,69 +1,69 @@ /* view/pivcardwiget.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2020 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include class QGridLayout; class QLabel; class QPushButton; namespace Kleo { namespace SmartCard { struct KeyPairInfo; class PIVCard; } // namespace SmartCard class PIVCardWidget: public QWidget { Q_OBJECT public: explicit PIVCardWidget(QWidget *parent = nullptr); - ~PIVCardWidget(); + ~PIVCardWidget() override; void setCard(const SmartCard::PIVCard* card); struct KeyWidgets { QLabel *keyGrip = nullptr; QLabel *keyAlgorithm = nullptr; QLabel *certificateInfo = nullptr; QPushButton *generateButton = nullptr; QPushButton *createCSRButton = nullptr; QPushButton *writeCertificateButton = nullptr; QPushButton *importCertificateButton = nullptr; QPushButton *writeKeyButton = nullptr; }; private: KeyWidgets createKeyWidgets(const SmartCard::KeyPairInfo &keyInfo); void updateKeyWidgets(const std::string &keyRef, const SmartCard::PIVCard *card); void generateKey(const std::string &keyref); void createCSR(const std::string &keyref); void writeCertificateToCard(const std::string &keyref); void importCertificateFromCard(const std::string &keyref); void writeKeyToCard(const std::string &keyref); void createKeyFromCardKeys(); void changePin(const std::string &keyRef); void setAdminKey(); private: std::string mCardSerialNumber; QLabel *mSerialNumber = nullptr; QLabel *mVersionLabel = nullptr; QPushButton *mKeyForCardKeysButton = nullptr; QMap mKeyWidgets; }; } // namespace Kleo diff --git a/src/view/searchbar.h b/src/view/searchbar.h index d5d0a91c7..081670cc0 100644 --- a/src/view/searchbar.h +++ b/src/view/searchbar.h @@ -1,58 +1,58 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/searchbar.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 class QLineEdit; namespace Kleo { class KeyFilter; class SearchBar : public QWidget { Q_OBJECT public: explicit SearchBar(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~SearchBar(); + ~SearchBar() override; const std::shared_ptr &keyFilter() const; QLineEdit *lineEdit() const; void updateClickMessage(const QString &shortcutStr); public Q_SLOTS: void setStringFilter(const QString &text); void setKeyFilter(const std::shared_ptr &filter); void setChangeStringFilterEnabled(bool enable); void setChangeKeyFilterEnabled(bool enable); Q_SIGNALS: void stringFilterChanged(const QString &text); void keyFilterChanged(const std::shared_ptr &filter); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void slotKeyFilterChanged(int)) Q_PRIVATE_SLOT(d, void listNotCertifiedKeys()) Q_PRIVATE_SLOT(d, void showOrHideCertifyButton()) }; } diff --git a/src/view/tabwidget.cpp b/src/view/tabwidget.cpp index 320efb65c..d2f72e965 100644 --- a/src/view/tabwidget.cpp +++ b/src/view/tabwidget.cpp @@ -1,960 +1,960 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/tabwidget.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 "tabwidget.h" #include "keytreeview.h" #include "kleopatra_debug.h" #include #include #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 GpgME; namespace { class Page : public Kleo::KeyTreeView { Q_OBJECT Page(const Page &other); public: Page(const QString &title, const QString &id, const QString &text, AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &toolTip = QString(), QWidget *parent = nullptr, const KConfigGroup &group = KConfigGroup()); Page(const KConfigGroup &group, QWidget *parent = nullptr); - ~Page(); + ~Page() override; void setTemporary(bool temporary); bool isTemporary() const { return m_isTemporary; } void setHierarchicalView(bool hierarchical) override; void setStringFilter(const QString &filter) override; void setKeyFilter(const std::shared_ptr &filter) override; QString title() const { return m_title.isEmpty() && keyFilter() ? keyFilter()->name() : m_title; } void setTitle(const QString &title); QString toolTip() const { return m_toolTip.isEmpty() ? title() : m_toolTip; } // not used void setToolTip(const QString &tip); bool canBeClosed() const { return m_canBeClosed; } bool canBeRenamed() const { return m_canBeRenamed; } bool canChangeStringFilter() const { return m_canChangeStringFilter; } bool canChangeKeyFilter() const { return m_canChangeKeyFilter && !m_isTemporary; } bool canChangeHierarchical() const { return m_canChangeHierarchical; } void saveTo(KConfigGroup &group) const; Page *clone() const override { return new Page(*this); } void liftAllRestrictions() { m_canBeClosed = m_canBeRenamed = m_canChangeStringFilter = m_canChangeKeyFilter = m_canChangeHierarchical = true; } Q_SIGNALS: void titleChanged(const QString &title); private: void init(); private: QString m_title; QString m_toolTip; bool m_isTemporary : 1; bool m_canBeClosed : 1; bool m_canBeRenamed : 1; bool m_canChangeStringFilter : 1; bool m_canChangeKeyFilter : 1; bool m_canChangeHierarchical : 1; }; } // anon namespace Page::Page(const Page &other) : KeyTreeView(other), m_title(other.m_title), m_toolTip(other.m_toolTip), m_isTemporary(other.m_isTemporary), m_canBeClosed(other.m_canBeClosed), m_canBeRenamed(other.m_canBeRenamed), m_canChangeStringFilter(other.m_canChangeStringFilter), m_canChangeKeyFilter(other.m_canChangeKeyFilter), m_canChangeHierarchical(other.m_canChangeHierarchical) { init(); } Page::Page(const QString &title, const QString &id, const QString &text, AbstractKeyListSortFilterProxyModel *proxy, const QString &toolTip, QWidget *parent, const KConfigGroup &group) : KeyTreeView(text, KeyFilterManager::instance()->keyFilterByID(id), proxy, parent, group), m_title(title), m_toolTip(toolTip), m_isTemporary(false), m_canBeClosed(true), m_canBeRenamed(true), m_canChangeStringFilter(true), m_canChangeKeyFilter(true), m_canChangeHierarchical(true) { init(); } static const char TITLE_ENTRY[] = "title"; static const char STRING_FILTER_ENTRY[] = "string-filter"; static const char KEY_FILTER_ENTRY[] = "key-filter"; static const char HIERARCHICAL_VIEW_ENTRY[] = "hierarchical-view"; static const char COLUMN_SIZES[] = "column-sizes"; static const char SORT_COLUMN[] = "sort-column"; static const char SORT_DESCENDING[] = "sort-descending"; Page::Page(const KConfigGroup &group, QWidget *parent) : KeyTreeView(group.readEntry(STRING_FILTER_ENTRY), KeyFilterManager::instance()->keyFilterByID(group.readEntry(KEY_FILTER_ENTRY)), nullptr, parent, group), m_title(group.readEntry(TITLE_ENTRY)), m_toolTip(), m_isTemporary(false), m_canBeClosed(!group.isImmutable()), m_canBeRenamed(!group.isEntryImmutable(TITLE_ENTRY)), m_canChangeStringFilter(!group.isEntryImmutable(STRING_FILTER_ENTRY)), m_canChangeKeyFilter(!group.isEntryImmutable(KEY_FILTER_ENTRY)), m_canChangeHierarchical(!group.isEntryImmutable(HIERARCHICAL_VIEW_ENTRY)) { init(); setHierarchicalView(group.readEntry(HIERARCHICAL_VIEW_ENTRY, true)); const QList settings = group.readEntry(COLUMN_SIZES, QList()); std::vector sizes; sizes.reserve(settings.size()); std::copy(settings.cbegin(), settings.cend(), std::back_inserter(sizes)); setColumnSizes(sizes); setSortColumn(group.readEntry(SORT_COLUMN, 0), group.readEntry(SORT_DESCENDING, true) ? Qt::DescendingOrder : Qt::AscendingOrder); } void Page::init() { } Page::~Page() {} void Page::saveTo(KConfigGroup &group) const { group.writeEntry(TITLE_ENTRY, m_title); group.writeEntry(STRING_FILTER_ENTRY, stringFilter()); group.writeEntry(KEY_FILTER_ENTRY, keyFilter() ? keyFilter()->id() : QString()); group.writeEntry(HIERARCHICAL_VIEW_ENTRY, isHierarchicalView()); QList settings; const auto sizes = columnSizes(); settings.reserve(sizes.size()); std::copy(sizes.cbegin(), sizes.cend(), std::back_inserter(settings)); group.writeEntry(COLUMN_SIZES, settings); group.writeEntry(SORT_COLUMN, sortColumn()); group.writeEntry(SORT_DESCENDING, sortOrder() == Qt::DescendingOrder); } void Page::setStringFilter(const QString &filter) { if (!m_canChangeStringFilter) { return; } KeyTreeView::setStringFilter(filter); } void Page::setKeyFilter(const std::shared_ptr &filter) { if (!canChangeKeyFilter()) { return; } const QString oldTitle = title(); KeyTreeView::setKeyFilter(filter); const QString newTitle = title(); if (oldTitle != newTitle) { Q_EMIT titleChanged(newTitle); } } void Page::setTitle(const QString &t) { if (t == m_title) { return; } if (!m_canBeRenamed) { return; } const QString oldTitle = title(); m_title = t; const QString newTitle = title(); if (oldTitle != newTitle) { Q_EMIT titleChanged(newTitle); } } #if 0 // not used void Page::setToolTip(const QString &tip) { if (tip == m_toolTip) { return; } if (!m_canBeRenamed) { return; } const QString oldTip = toolTip(); m_toolTip = tip; const QString newTip = toolTip(); if (oldTip != newTip) { Q_EMIT titleChanged(title()); } } #endif void Page::setHierarchicalView(bool on) { if (!m_canChangeHierarchical) { return; } KeyTreeView::setHierarchicalView(on); } void Page::setTemporary(bool on) { if (on == m_isTemporary) { return; } m_isTemporary = on; if (on) { setKeyFilter(std::shared_ptr()); } } // // // TabWidget // // class TabWidget::Private { friend class ::Kleo::TabWidget; TabWidget *const q; public: explicit Private(TabWidget *qq); ~Private() {} private: void slotContextMenu(const QPoint &p); void currentIndexChanged(int index); void slotPageTitleChanged(const QString &title); void slotPageKeyFilterChanged(const std::shared_ptr &filter); void slotPageStringFilterChanged(const QString &filter); void slotPageHierarchyChanged(bool on); #ifndef QT_NO_INPUTDIALOG void slotRenameCurrentTab() { renamePage(currentPage()); } #endif // QT_NO_INPUTDIALOG void slotNewTab(); void slotDuplicateCurrentTab() { duplicatePage(currentPage()); } void slotCloseCurrentTab() { closePage(currentPage()); } void slotMoveCurrentTabLeft() { movePageLeft(currentPage()); } void slotMoveCurrentTabRight() { movePageRight(currentPage()); } void slotToggleHierarchicalView(bool on) { toggleHierarchicalView(currentPage(), on); } void slotExpandAll() { expandAll(currentPage()); } void slotCollapseAll() { collapseAll(currentPage()); } #ifndef QT_NO_INPUTDIALOG void renamePage(Page *page); #endif void duplicatePage(Page *page); void closePage(Page *page); void movePageLeft(Page *page); void movePageRight(Page *page); void toggleHierarchicalView(Page *page, bool on); void expandAll(Page *page); void collapseAll(Page *page); void enableDisableCurrentPageActions(); void enableDisablePageActions(const std::vector &actions, const Page *page); Page *currentPage() const { Q_ASSERT(!tabWidget.currentWidget() || qobject_cast(tabWidget.currentWidget())); return static_cast(tabWidget.currentWidget()); } Page *page(unsigned int idx) const { Q_ASSERT(!tabWidget.widget(idx) || qobject_cast(tabWidget.widget(idx))); return static_cast(tabWidget.widget(idx)); } Page *senderPage() const { QObject *const sender = q->sender(); Q_ASSERT(!sender || qobject_cast(sender)); return static_cast(sender); } bool isSenderCurrentPage() const { Page *const sp = senderPage(); return sp && sp == currentPage(); } QTreeView *addView(Page *page, Page *columnReference); void setCornerAction(QAction *action, Qt::Corner corner); private: AbstractKeyListModel *flatModel; AbstractKeyListModel *hierarchicalModel; QTabWidget tabWidget; QVBoxLayout layout; enum { Rename, Duplicate, Close, MoveLeft, MoveRight, Hierarchical, ExpandAll, CollapseAll, NumPageActions }; QAction *newAction = nullptr; std::vector currentPageActions; std::vector otherPageActions; bool actionsCreated; }; TabWidget::Private::Private(TabWidget *qq) : q(qq), flatModel(nullptr), hierarchicalModel(nullptr), tabWidget(q), layout(q), actionsCreated(false) { KDAB_SET_OBJECT_NAME(tabWidget); KDAB_SET_OBJECT_NAME(layout); layout.setContentsMargins(0, 0, 0, 0); layout.addWidget(&tabWidget); tabWidget.tabBar()->hide(); tabWidget.setMovable(true); tabWidget.tabBar()->setContextMenuPolicy(Qt::CustomContextMenu); connect(&tabWidget, SIGNAL(currentChanged(int)), q, SLOT(currentIndexChanged(int))); connect(tabWidget.tabBar(), &QWidget::customContextMenuRequested, q, [this](const QPoint & p) { slotContextMenu(p); }); } void TabWidget::Private::slotContextMenu(const QPoint &p) { const int tabUnderPos = tabWidget.tabBar()->tabAt(p); Page *const contextMenuPage = static_cast(tabWidget.widget(tabUnderPos)); const Page *const current = currentPage(); const std::vector actions = contextMenuPage == current ? currentPageActions : otherPageActions; enableDisablePageActions(actions, contextMenuPage); QMenu menu; menu.addAction(actions[Rename]); menu.addSeparator(); menu.addAction(newAction); menu.addAction(actions[Duplicate]); menu.addSeparator(); menu.addAction(actions[MoveLeft]); menu.addAction(actions[MoveRight]); menu.addSeparator(); menu.addAction(actions[Close]); const QAction *const action = menu.exec(tabWidget.tabBar()->mapToGlobal(p)); if (contextMenuPage == current || action == newAction) { return; // performed through signal/slot connections... } #ifndef QT_NO_INPUTDIALOG if (action == otherPageActions[Rename]) { renamePage(contextMenuPage); } #endif // QT_NO_INPUTDIALOG else if (action == otherPageActions[Duplicate]) { duplicatePage(contextMenuPage); } else if (action == otherPageActions[Close]) { closePage(contextMenuPage); } else if (action == otherPageActions[MoveLeft]) { movePageLeft(contextMenuPage); } else if (action == otherPageActions[MoveRight]) { movePageRight(contextMenuPage); } } void TabWidget::Private::currentIndexChanged(int index) { const Page *const page = this->page(index); Q_EMIT q->currentViewChanged(page ? page->view() : nullptr); Q_EMIT q->keyFilterChanged(page ? page->keyFilter() : std::shared_ptr()); Q_EMIT q->stringFilterChanged(page ? page->stringFilter() : QString()); enableDisableCurrentPageActions(); } void TabWidget::Private::enableDisableCurrentPageActions() { const Page *const page = currentPage(); Q_EMIT q->enableChangeStringFilter(page && page->canChangeStringFilter()); Q_EMIT q->enableChangeKeyFilter(page && page->canChangeKeyFilter()); enableDisablePageActions(currentPageActions, page); } void TabWidget::Private::enableDisablePageActions(const std::vector &actions, const Page *p) { actions[Rename] ->setEnabled(p && p->canBeRenamed()); actions[Duplicate] ->setEnabled(p); actions[Close] ->setEnabled(p && p->canBeClosed() && tabWidget.count() > 1); actions[MoveLeft] ->setEnabled(p && tabWidget.indexOf(const_cast(p)) != 0); actions[MoveRight] ->setEnabled(p && tabWidget.indexOf(const_cast(p)) != tabWidget.count() - 1); actions[Hierarchical]->setEnabled(p && p->canChangeHierarchical()); actions[Hierarchical]->setChecked(p && p->isHierarchicalView()); actions[ExpandAll] ->setEnabled(p && p->isHierarchicalView()); actions[CollapseAll] ->setEnabled(p && p->isHierarchicalView()); if (tabWidget.count() < 2) { tabWidget.tabBar()->hide(); } else { tabWidget.tabBar()->show(); } } void TabWidget::Private::slotPageTitleChanged(const QString &) { if (Page *const page = senderPage()) { const int idx = tabWidget.indexOf(page); tabWidget.setTabText(idx, page->title()); tabWidget.setTabToolTip(idx, page->toolTip()); } } void TabWidget::Private::slotPageKeyFilterChanged(const std::shared_ptr &kf) { if (isSenderCurrentPage()) { Q_EMIT q->keyFilterChanged(kf); } } void TabWidget::Private::slotPageStringFilterChanged(const QString &filter) { if (isSenderCurrentPage()) { Q_EMIT q->stringFilterChanged(filter); } } void TabWidget::Private::slotPageHierarchyChanged(bool) { enableDisableCurrentPageActions(); } void TabWidget::Private::slotNewTab() { const KConfigGroup group = KSharedConfig::openConfig()->group(QString::asprintf("View #%u", tabWidget.count())); Page *page = new Page(QString(), QStringLiteral("all-certificates"), QString(), nullptr, QString(), nullptr, group); addView(page, currentPage()); tabWidget.setCurrentIndex(tabWidget.count() - 1); } void TabWidget::Private::renamePage(Page *page) { if (!page) { return; } bool ok; const QString text = QInputDialog::getText(q, i18n("Rename Tab"), i18n("New tab title:"), QLineEdit::Normal, page->title(), &ok); if (!ok) { return; } page->setTitle(text); } void TabWidget::Private::duplicatePage(Page *page) { if (!page) { return; } Page *const clone = page->clone(); Q_ASSERT(clone); clone->liftAllRestrictions(); addView(clone, page); } void TabWidget::Private::closePage(Page *page) { if (!page || !page->canBeClosed() || tabWidget.count() <= 1) { return; } Q_EMIT q->viewAboutToBeRemoved(page->view()); tabWidget.removeTab(tabWidget.indexOf(page)); enableDisableCurrentPageActions(); } void TabWidget::Private::movePageLeft(Page *page) { if (!page) { return; } const int idx = tabWidget.indexOf(page); if (idx <= 0) { return; } tabWidget.tabBar()->moveTab(idx, idx - 1); enableDisableCurrentPageActions(); } void TabWidget::Private::movePageRight(Page *page) { if (!page) { return; } const int idx = tabWidget.indexOf(page); if (idx < 0 || idx >= tabWidget.count() - 1) { return; } tabWidget.tabBar()->moveTab(idx, idx + 1); enableDisableCurrentPageActions(); } void TabWidget::Private::toggleHierarchicalView(Page *page, bool on) { if (!page) { return; } page->setHierarchicalView(on); } void TabWidget::Private::expandAll(Page *page) { if (!page || !page->view()) { return; } page->view()->expandAll(); } void TabWidget::Private::collapseAll(Page *page) { if (!page || !page->view()) { return; } page->view()->collapseAll(); } TabWidget::TabWidget(QWidget *p, Qt::WindowFlags f) : QWidget(p, f), d(new Private(this)) { } TabWidget::~TabWidget() { saveViews(KSharedConfig::openConfig().data()); } void TabWidget::setFlatModel(AbstractKeyListModel *model) { if (model == d->flatModel) { return; } d->flatModel = model; for (unsigned int i = 0, end = count(); i != end; ++i) if (Page *const page = d->page(i)) { page->setFlatModel(model); } } AbstractKeyListModel *TabWidget::flatModel() const { return d->flatModel; } void TabWidget::setHierarchicalModel(AbstractKeyListModel *model) { if (model == d->hierarchicalModel) { return; } d->hierarchicalModel = model; for (unsigned int i = 0, end = count(); i != end; ++i) if (Page *const page = d->page(i)) { page->setHierarchicalModel(model); } } AbstractKeyListModel *TabWidget::hierarchicalModel() const { return d->hierarchicalModel; } void TabWidget::Private::setCornerAction(QAction *action, Qt::Corner corner) { if (!action) { return; } auto b = new QToolButton; b->setDefaultAction(action); tabWidget.setCornerWidget(b, corner); } void TabWidget::setStringFilter(const QString &filter) { if (Page *const page = d->currentPage()) { page->setStringFilter(filter); } } void TabWidget::setKeyFilter(const std::shared_ptr &filter) { if (!filter) { qCDebug(KLEOPATRA_LOG) << "TabWidget::setKeyFilter() trial to set filter=NULL"; return; } if (Page *const page = d->currentPage()) { page->setKeyFilter(filter); } } std::vector TabWidget::views() const { std::vector result; const unsigned int N = count(); result.reserve(N); for (unsigned int i = 0; i != N; ++i) if (const Page *const p = d->page(i)) { result.push_back(p->view()); } return result; } QAbstractItemView *TabWidget::currentView() const { if (Page *const page = d->currentPage()) { return page->view(); } else { return nullptr; } } KeyListModelInterface *TabWidget::currentModel() const { const QAbstractItemView *const view = currentView(); if (!view) { return nullptr; } auto const proxy = qobject_cast(view->model()); if (!proxy) { return nullptr; } return dynamic_cast(proxy); } unsigned int TabWidget::count() const { return d->tabWidget.count(); } void TabWidget::setMultiSelection(bool on) { for (unsigned int i = 0, end = count(); i != end; ++i) if (const Page *const p = d->page(i)) if (QTreeView *const view = p->view()) { view->setSelectionMode(on ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection); } } void TabWidget::createActions(KActionCollection *coll) { if (!coll) { return; } const action_data actionDataNew = { "window_new_tab", i18n("New Tab"), i18n("Open a new tab"), "tab-new-background", this, SLOT(slotNewTab()), QStringLiteral("CTRL+SHIFT+N"), false, true }; d->newAction = make_action_from_data(actionDataNew, coll); struct action_data actionData[] = { { "window_rename_tab", i18n("Rename Tab..."), i18n("Rename this tab"), "edit-rename", this, SLOT(slotRenameCurrentTab()), QStringLiteral("CTRL+SHIFT+R"), false, false }, { "window_duplicate_tab", i18n("Duplicate Tab"), i18n("Duplicate this tab"), "tab-duplicate", this, SLOT(slotDuplicateCurrentTab()), QStringLiteral("CTRL+SHIFT+D"), false, true }, { "window_close_tab", i18n("Close Tab"), i18n("Close this tab"), "tab-close", this, SLOT(slotCloseCurrentTab()), QStringLiteral("CTRL+SHIFT+W"), false, false }, // ### CTRL-W when available { "window_move_tab_left", i18n("Move Tab Left"), i18n("Move this tab left"), nullptr, this, SLOT(slotMoveCurrentTabLeft()), QStringLiteral("CTRL+SHIFT+LEFT"), false, false }, { "window_move_tab_right", i18n("Move Tab Right"), i18n("Move this tab right"), nullptr, this, SLOT(slotMoveCurrentTabRight()), QStringLiteral("CTRL+SHIFT+RIGHT"), false, false }, { "window_view_hierarchical", i18n("Hierarchical Certificate List"), QString(), nullptr, this, SLOT(slotToggleHierarchicalView(bool)), QString(), true, false }, { "window_expand_all", i18n("Expand All"), QString(), nullptr, this, SLOT(slotExpandAll()), QStringLiteral("CTRL+."), false, false }, { "window_collapse_all", i18n("Collapse All"), QString(), nullptr, this, SLOT(slotCollapseAll()), QStringLiteral("CTRL+,"), false, false }, }; d->currentPageActions.reserve(d->NumPageActions); for (int i = 0; i < d->NumPageActions; ++i) { d->currentPageActions.push_back(make_action_from_data(actionData[i], coll)); } d->otherPageActions.reserve(d->NumPageActions); for (int i = 0; i < d->NumPageActions; ++i) { // create actions for the context menu of the currently not active tabs, // but do not add those actions to the action collection const action_data ad = actionData[i]; auto action = new QAction(ad.text, coll); if (ad.icon) { action->setIcon(QIcon::fromTheme(QLatin1String(ad.icon))); } action->setEnabled(ad.enabled); d->otherPageActions.push_back(action); } d->setCornerAction(d->newAction, Qt::TopLeftCorner); d->setCornerAction(d->currentPageActions[d->Close], Qt::TopRightCorner); d->actionsCreated = true; } QAbstractItemView *TabWidget::addView(const QString &title, const QString &id, const QString &text) { const KConfigGroup group = KSharedConfig::openConfig()->group(QString::asprintf("View #%u", d->tabWidget.count())); Page *page = new Page(title, id, text, nullptr, QString(), nullptr, group); return d->addView(page, d->currentPage()); } QAbstractItemView *TabWidget::addView(const KConfigGroup &group) { return d->addView(new Page(group), nullptr); } QAbstractItemView *TabWidget::addTemporaryView(const QString &title, AbstractKeyListSortFilterProxyModel *proxy, const QString &tabToolTip) { const KConfigGroup group = KSharedConfig::openConfig()->group("KeyTreeView_default"); Page *const page = new Page(title, QString(), QString(), proxy, tabToolTip, nullptr, group); page->setTemporary(true); QAbstractItemView *v = d->addView(page, d->currentPage()); d->tabWidget.setCurrentIndex(d->tabWidget.count() - 1); return v; } QTreeView *TabWidget::Private::addView(Page *page, Page *columnReference) { if (!page) { return nullptr; } if (!actionsCreated) { auto coll = new KActionCollection(q); q->createActions(coll); } page->setFlatModel(flatModel); page->setHierarchicalModel(hierarchicalModel); connect(page, SIGNAL(titleChanged(QString)), q, SLOT(slotPageTitleChanged(QString))); connect(page, SIGNAL(keyFilterChanged(std::shared_ptr)), q, SLOT(slotPageKeyFilterChanged(std::shared_ptr))); connect(page, SIGNAL(stringFilterChanged(QString)), q, SLOT(slotPageStringFilterChanged(QString))); connect(page, SIGNAL(hierarchicalChanged(bool)), q, SLOT(slotPageHierarchyChanged(bool))); if (columnReference) { page->setColumnSizes(columnReference->columnSizes()); page->setSortColumn(columnReference->sortColumn(), columnReference->sortOrder()); } QAbstractItemView *const previous = q->currentView(); const int tabIndex = tabWidget.addTab(page, page->title()); tabWidget.setTabToolTip(tabIndex, page->toolTip()); // work around a bug in QTabWidget (tested with 4.3.2) not emitting currentChanged() when the first widget is inserted QAbstractItemView *const current = q->currentView(); if (previous != current) { currentIndexChanged(tabWidget.currentIndex()); } enableDisableCurrentPageActions(); QTreeView *view = page->view(); Q_EMIT q->viewAdded(view); return view; } static QStringList extractViewGroups(const KConfig *config) { return config ? config->groupList().filter(QRegularExpression(QStringLiteral("^View #\\d+$"))) : QStringList(); } // work around deleteGroup() not deleting groups out of groupList(): static const bool KCONFIG_DELETEGROUP_BROKEN = true; void TabWidget::loadViews(const KConfig *config) { if (config) { QStringList groupList = extractViewGroups(config); groupList.sort(); for (const QString &group : std::as_const(groupList)) { const KConfigGroup kcg(config, group); if (!KCONFIG_DELETEGROUP_BROKEN || kcg.readEntry("magic", 0U) == 0xFA1AFE1U) { addView(kcg); } } } if (!count()) { // add default view: addView(QString(), QStringLiteral("all-certificates")); } } void TabWidget::saveViews(KConfig *config) const { if (!config) { return; } const auto extraView{extractViewGroups(config)}; for (const QString &group : extraView) { config->deleteGroup(group); } unsigned int vg = 0; for (unsigned int i = 0, end = count(); i != end; ++i) { if (const Page *const p = d->page(i)) { if (p->isTemporary()) { continue; } KConfigGroup group(config, QString::asprintf("View #%u", vg++)); p->saveTo(group); if (KCONFIG_DELETEGROUP_BROKEN) { group.writeEntry("magic", 0xFA1AFE1U); } } } } static void xconnect(const QObject *o1, const char *signal, const QObject *o2, const char *slot) { QObject::connect(o1, signal, o2, slot); QObject::connect(o2, signal, o1, slot); } void TabWidget::connectSearchBar(QObject *sb) { xconnect(sb, SIGNAL(stringFilterChanged(QString)), this, SLOT(setStringFilter(QString))); xconnect(sb, SIGNAL(keyFilterChanged(std::shared_ptr)), this, SLOT(setKeyFilter(std::shared_ptr))); connect(this, SIGNAL(enableChangeStringFilter(bool)), sb, SLOT(setChangeStringFilterEnabled(bool))); connect(this, SIGNAL(enableChangeKeyFilter(bool)), sb, SLOT(setChangeKeyFilterEnabled(bool))); } #include "moc_tabwidget.cpp" #include "tabwidget.moc" diff --git a/src/view/tabwidget.h b/src/view/tabwidget.h index cbae9bc84..762aa4109 100644 --- a/src/view/tabwidget.h +++ b/src/view/tabwidget.h @@ -1,100 +1,100 @@ /* -*- mode: c++; c-basic-offset:4 -*- view/tabwidget.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 class QAbstractItemView; class KConfigGroup; class KActionCollection; class KConfig; namespace Kleo { class AbstractKeyListModel; class AbstractKeyListSortFilterProxyModel; class KeyFilter; class KeyListModelInterface; class TabWidget : public QWidget { Q_OBJECT public: explicit TabWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {}); - ~TabWidget(); + ~TabWidget() override; void setFlatModel(AbstractKeyListModel *model); AbstractKeyListModel *flatModel() const; void setHierarchicalModel(AbstractKeyListModel *model); AbstractKeyListModel *hierarchicalModel() const; QAbstractItemView *addView(const QString &title = QString(), const QString &keyFilterID = QString(), const QString &searchString = QString()); QAbstractItemView *addView(const KConfigGroup &group); QAbstractItemView *addTemporaryView(const QString &title = QString(), AbstractKeyListSortFilterProxyModel *proxy = nullptr, const QString &tabToolTip = QString()); void loadViews(const KConfig *cfg); void saveViews(KConfig *cfg) const; std::vector views() const; QAbstractItemView *currentView() const; KeyListModelInterface *currentModel() const; unsigned int count() const; void createActions(KActionCollection *collection); void connectSearchBar(QObject *sb); void setMultiSelection(bool on); public Q_SLOTS: void setKeyFilter(const std::shared_ptr &filter); void setStringFilter(const QString &filter); Q_SIGNALS: void viewAdded(QAbstractItemView *view); void viewAboutToBeRemoved(QAbstractItemView *view); void currentViewChanged(QAbstractItemView *view); void stringFilterChanged(const QString &filter); void keyFilterChanged(const std::shared_ptr &filter); void enableChangeStringFilter(bool enable); void enableChangeKeyFilter(bool enable); private: class Private; kdtools::pimpl_ptr d; Q_PRIVATE_SLOT(d, void currentIndexChanged(int)) Q_PRIVATE_SLOT(d, void slotPageTitleChanged(const QString &)) Q_PRIVATE_SLOT(d, void slotPageKeyFilterChanged(const std::shared_ptr &)) Q_PRIVATE_SLOT(d, void slotPageStringFilterChanged(const QString &)) Q_PRIVATE_SLOT(d, void slotPageHierarchyChanged(bool)) Q_PRIVATE_SLOT(d, void slotRenameCurrentTab()) Q_PRIVATE_SLOT(d, void slotNewTab()) Q_PRIVATE_SLOT(d, void slotDuplicateCurrentTab()) Q_PRIVATE_SLOT(d, void slotCloseCurrentTab()) Q_PRIVATE_SLOT(d, void slotMoveCurrentTabLeft()) Q_PRIVATE_SLOT(d, void slotMoveCurrentTabRight()) Q_PRIVATE_SLOT(d, void slotToggleHierarchicalView(bool)) Q_PRIVATE_SLOT(d, void slotExpandAll()) Q_PRIVATE_SLOT(d, void slotCollapseAll()) }; } diff --git a/src/view/waitwidget.h b/src/view/waitwidget.h index 5bf679b98..de0746907 100644 --- a/src/view/waitwidget.h +++ b/src/view/waitwidget.h @@ -1,29 +1,29 @@ /* SPDX-FileCopyrightText: 2017 Intevation GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include class QLabel; namespace Kleo { class WaitWidget: public QWidget { Q_OBJECT public: explicit WaitWidget(QWidget *parent = nullptr); - ~WaitWidget(); + ~WaitWidget() override; void setText(const QString &text); private: QLabel *mLabel; }; } // namespace Kleo