diff --git a/src/commands/exportopenpgpcertstoservercommand.cpp b/src/commands/exportopenpgpcertstoservercommand.cpp index 844fdc8c8..8d24fb248 100644 --- a/src/commands/exportopenpgpcertstoservercommand.cpp +++ b/src/commands/exportopenpgpcertstoservercommand.cpp @@ -1,131 +1,136 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/exportopenpgpcertstoservercommand.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 "exportopenpgpcertstoservercommand.h" #include "command_p.h" #include #include #include #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; ExportOpenPGPCertsToServerCommand::ExportOpenPGPCertsToServerCommand(KeyListController *c) : GnuPGProcessCommand(c) { } ExportOpenPGPCertsToServerCommand::ExportOpenPGPCertsToServerCommand(QAbstractItemView *v, KeyListController *c) : GnuPGProcessCommand(v, c) { } ExportOpenPGPCertsToServerCommand::ExportOpenPGPCertsToServerCommand(const Key &key) : GnuPGProcessCommand(key) { } +ExportOpenPGPCertsToServerCommand::ExportOpenPGPCertsToServerCommand(const std::vector &keys) + : GnuPGProcessCommand(keys) +{ +} + ExportOpenPGPCertsToServerCommand::~ExportOpenPGPCertsToServerCommand() = default; bool ExportOpenPGPCertsToServerCommand::preStartHook(QWidget *parent) const { if (!haveKeyserverConfigured()) if (KMessageBox::warningContinueCancel(parent, xi18nc("@info", "No OpenPGP directory services have been configured." "Since none is configured, Kleopatra will use " "keys.gnupg.net as the server to export to." "You can configure OpenPGP directory servers in Kleopatra's " "configuration dialog." "Do you want to continue with keys.gnupg.net " "as the server to export to?"), i18nc("@title:window", "OpenPGP Certificate Export"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("warn-export-openpgp-missing-keyserver")) != KMessageBox::Continue) { return false; } return KMessageBox::warningContinueCancel(parent, xi18nc("@info", "When OpenPGP certificates have been exported to a public directory server, " "it is nearly impossible to remove them again." "Before exporting your certificate to a public directory server, make sure that you " "have created a revocation certificate so you can revoke the certificate if needed later." "Are you sure you want to continue?"), i18nc("@title:window", "OpenPGP Certificate Export"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("warn-export-openpgp-nonrevocable")) == KMessageBox::Continue; } QStringList ExportOpenPGPCertsToServerCommand::arguments() const { QStringList result; result << gpgPath(); if (!haveKeyserverConfigured()) { result << QStringLiteral("--keyserver") << QStringLiteral("keys.gnupg.net"); } result << QStringLiteral("--send-keys"); const auto keys = d->keys(); for (const Key &key : keys) { result << QLatin1String(key.primaryFingerprint()); } return result; } QString ExportOpenPGPCertsToServerCommand::errorCaption() const { return i18nc("@title:window", "OpenPGP Certificate Export Error"); } QString ExportOpenPGPCertsToServerCommand::successCaption() const { return i18nc("@title:window", "OpenPGP Certificate Export Finished"); } QString ExportOpenPGPCertsToServerCommand::crashExitMessage(const QStringList &args) const { return xi18nc("@info", "The GPG process that tried to export OpenPGP certificates " "ended prematurely because of an unexpected error." "Please check the output of %1 for details.", args.join(QLatin1Char(' '))); } QString ExportOpenPGPCertsToServerCommand::errorExitMessage(const QStringList &args) const { // ki18n(" ") as initializer because initializing with empty string leads to // (I18N_EMPTY_MESSAGE) const auto errorLines = errorString().split(QLatin1Char{'\n'}); const auto errorText = std::accumulate(errorLines.begin(), errorLines.end(), KLocalizedString{ki18n(" ")}, [](KLocalizedString temp, const auto &line) { return kxi18nc("@info used for concatenating multiple lines of text with line breaks; most likely this shouldn't be translated", "%1%2") .subs(temp) .subs(line); }); return xi18nc("@info", "An error occurred while trying to export OpenPGP certificates. " "The output of %1 was:%2", args[0], errorText); } QString ExportOpenPGPCertsToServerCommand::successMessage(const QStringList &) const { return i18nc("@info", "OpenPGP certificates exported successfully."); } diff --git a/src/commands/exportopenpgpcertstoservercommand.h b/src/commands/exportopenpgpcertstoservercommand.h index 3535f1ab8..6e2adecd1 100644 --- a/src/commands/exportopenpgpcertstoservercommand.h +++ b/src/commands/exportopenpgpcertstoservercommand.h @@ -1,48 +1,49 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/exportopenpgpcertstoservercommand.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 Commands { class ExportOpenPGPCertsToServerCommand : public GnuPGProcessCommand { Q_OBJECT public: - explicit ExportOpenPGPCertsToServerCommand(QAbstractItemView *view, KeyListController *parent); + ExportOpenPGPCertsToServerCommand(QAbstractItemView *view, KeyListController *parent); explicit ExportOpenPGPCertsToServerCommand(KeyListController *parent); explicit ExportOpenPGPCertsToServerCommand(const GpgME::Key &key); + explicit ExportOpenPGPCertsToServerCommand(const std::vector &keys); ~ExportOpenPGPCertsToServerCommand() override; static Restrictions restrictions() { return MustBeOpenPGP; } private: bool preStartHook(QWidget *) const override; QStringList arguments() const override; QString errorCaption() const override; QString successCaption() const override; QString crashExitMessage(const QStringList &) const override; QString errorExitMessage(const QStringList &) const override; QString successMessage(const QStringList &) const override; }; } } diff --git a/src/commands/gnupgprocesscommand.cpp b/src/commands/gnupgprocesscommand.cpp index 335b42451..ad326841c 100644 --- a/src/commands/gnupgprocesscommand.cpp +++ b/src/commands/gnupgprocesscommand.cpp @@ -1,392 +1,398 @@ /* -*- 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() 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(); } } 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(); } +GnuPGProcessCommand::GnuPGProcessCommand(const std::vector &keys) + : Command(keys, new Private(this, nullptr)) +{ + d->init(); +} + void GnuPGProcessCommand::Private::init() { #if QT_DEPRECATED_SINCE(5, 13) connect(&process, qOverload(&QProcess::finished), #else connect(&process, &QProcess::finished, #endif q, [this](int exitCode, QProcess::ExitStatus status) { slotProcessFinished(exitCode, status); }); q->m_procReadyReadStdErrConnection = connect(&process, &QProcess::readyReadStandardError, q, [this]() { 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 "gnupgprocesscommand.moc" #include "moc_gnupgprocesscommand.cpp" diff --git a/src/commands/gnupgprocesscommand.h b/src/commands/gnupgprocesscommand.h index b8117661e..58d9eacdb 100644 --- a/src/commands/gnupgprocesscommand.h +++ b/src/commands/gnupgprocesscommand.h @@ -1,70 +1,71 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/gnupgprocesscommand.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; class QProcess; namespace Kleo { namespace Commands { class GnuPGProcessCommand : public Command { Q_OBJECT protected: - explicit GnuPGProcessCommand(QAbstractItemView *view, KeyListController *parent); + GnuPGProcessCommand(QAbstractItemView *view, KeyListController *parent); explicit GnuPGProcessCommand(KeyListController *parent); explicit GnuPGProcessCommand(const GpgME::Key &key); + explicit GnuPGProcessCommand(const std::vector &keys); ~GnuPGProcessCommand() override; public: QDialog *dialog() const; void setShowsOutputWindow(bool show); private: virtual bool preStartHook(QWidget *parentWidget) const; virtual QStringList arguments() const = 0; virtual QString errorCaption() const = 0; virtual QString successCaption() const; virtual QString crashExitMessage(const QStringList &args) const = 0; virtual QString errorExitMessage(const QStringList &args) const = 0; virtual QString successMessage(const QStringList &args) const; virtual void postSuccessHook(QWidget *parentWidget); protected: QString errorString() const; void setIgnoresSuccessOrFailure(bool ignore); bool ignoresSuccessOrFailure() const; bool showsOutputWindow() const; QProcess *process(); void doStart() override; void doCancel() override; QMetaObject::Connection m_procReadyReadStdErrConnection; private: class Private; inline Private *d_func(); inline const Private *d_func() const; }; } }