From c64a8daf507a2216611861a12f312466b0bae8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Wed, 4 May 2022 14:51:50 +0200 Subject: [PATCH] qt: Emit import result when refreshing OpenPGP keys * lang/qt/src/refreshopenpgpkeysjob.h: New. * lang/qt/src/Makefile.am, lang/qt/src/job.cpp: Update accordingly. * lang/qt/src/qgpgmerefreshopenpgpkeysjob.h (class QGpgMERefreshOpenPGPKeysJob): Derive from RefreshOpenPGPKeysJob with result ImportResult. Remove unused start overload. * lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp (locate_external_keys): Ignore result of KeyListJob. Return import result. (receive_keys): Return import result. (refresh_keys): Merge the two import results and return the result. * lang/qt/src/protocol.h (class Protocol): Add pure virtual member function refreshOpenPGPKeysJob. * lang/qt/src/protocol_p.h (Protocol::refreshKeysJob): Return nullptr for OpenPGP protocol. (Protocol::refreshOpenPGPKeysJob): New. * lang/qt/tests/run-refreshkeysjob.cpp (main): Use appropriate job for the protocol of the key to refresh. -- This adds RefreshOpenPGPKeysJob complementing RefreshKeysJob (for S/MIME keys). Changing the result type of RefreshKeysJob would break the ABI. Therefore we have to introduce a new base class for the refresh job for OpenPGP. We derive this base class from AbstractImportJob because we want to return an import result. GnuPG-bug-id: 5951 --- lang/qt/src/Makefile.am | 3 + lang/qt/src/job.cpp | 3 + lang/qt/src/protocol.h | 12 +++- lang/qt/src/protocol_p.h | 13 +++- lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp | 30 +++++---- lang/qt/src/qgpgmerefreshopenpgpkeysjob.h | 15 +++-- lang/qt/src/refreshopenpgpkeysjob.h | 67 +++++++++++++++++++++ lang/qt/tests/run-refreshkeysjob.cpp | 47 ++++++++++----- 8 files changed, 148 insertions(+), 42 deletions(-) create mode 100644 lang/qt/src/refreshopenpgpkeysjob.h diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 18456d54..5a41a318 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -79,6 +79,7 @@ qgpgme_headers= \ signencryptjob.h \ verifyopaquejob.h \ refreshkeysjob.h \ + refreshopenpgpkeysjob.h \ cryptoconfig.h \ deletejob.h \ importfromkeyserverjob.h \ @@ -124,6 +125,7 @@ camelcase_headers= \ SignEncryptJob \ VerifyOpaqueJob \ RefreshKeysJob \ + RefreshOpenPGPKeysJob \ CryptoConfig \ DeleteJob \ ImportFromKeyserverJob \ @@ -231,6 +233,7 @@ qgpgme_moc_sources = \ qgpgmetofupolicyjob.moc \ receivekeysjob.moc \ refreshkeysjob.moc \ + refreshopenpgpkeysjob.moc \ revokekeyjob.moc \ signencryptjob.moc \ signjob.moc \ diff --git a/lang/qt/src/job.cpp b/lang/qt/src/job.cpp index dba7556b..4a379f12 100644 --- a/lang/qt/src/job.cpp +++ b/lang/qt/src/job.cpp @@ -61,6 +61,7 @@ #include "downloadjob.h" #include "deletejob.h" #include "refreshkeysjob.h" +#include "refreshopenpgpkeysjob.h" #include "addexistingsubkeyjob.h" #include "adduseridjob.h" #include "specialjob.h" @@ -157,6 +158,7 @@ make_job_subclass(AbstractImportJob) make_job_subclass_ext(ImportJob, AbstractImportJob) make_job_subclass_ext(ImportFromKeyserverJob, AbstractImportJob) make_job_subclass_ext(ReceiveKeysJob, AbstractImportJob) +make_job_subclass_ext(RefreshOpenPGPKeysJob, AbstractImportJob) make_job_subclass(ExportJob) make_job_subclass(ChangeExpiryJob) make_job_subclass(ChangeOwnerTrustJob) @@ -200,6 +202,7 @@ make_job_subclass(RevokeKeyJob) #include "downloadjob.moc" #include "deletejob.moc" #include "refreshkeysjob.moc" +#include "refreshopenpgpkeysjob.moc" #include "addexistingsubkeyjob.moc" #include "adduseridjob.moc" #include "specialjob.moc" diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index d8500174..f0772eef 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -59,6 +59,7 @@ class VerifyOpaqueJob; class SignEncryptJob; class DecryptVerifyJob; class RefreshKeysJob; +class RefreshOpenPGPKeysJob; class ChangeExpiryJob; class ChangeOwnerTrustJob; class ChangePasswdJob; @@ -139,9 +140,7 @@ public: /** * For S/MIME keys this job performs a full validation check of the keys * with updated CRLs. - * For OpenPGP keys this job performs a refresh of keys via the external - * methods as defined by the \c auto-key-locate option and from the - * configured keyserver. + * For OpenPGP keys, use refreshOpenPGPKeysJob. */ virtual RefreshKeysJob *refreshKeysJob() const = 0; virtual ChangeExpiryJob *changeExpiryJob() const = 0; @@ -184,6 +183,13 @@ public: virtual ReceiveKeysJob *receiveKeysJob() const = 0; virtual RevokeKeyJob *revokeKeyJob() const = 0; + + /** + * This job performs a refresh of OpenPGP keys via the external methods + * as defined by the \c auto-key-locate option and via an import from the + * configured keyserver. + */ + virtual RefreshOpenPGPKeysJob *refreshOpenPGPKeysJob() const = 0; }; /** Obtain a reference to the OpenPGP Protocol. diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h index 56c296c0..36cb7199 100644 --- a/lang/qt/src/protocol_p.h +++ b/lang/qt/src/protocol_p.h @@ -284,8 +284,17 @@ public: QGpgME::RefreshKeysJob *refreshKeysJob() const Q_DECL_OVERRIDE { - if (mProtocol == GpgME::CMS) { - return new QGpgME::QGpgMERefreshSMIMEKeysJob; + if (mProtocol != GpgME::CMS) { + return nullptr; + } + + return new QGpgME::QGpgMERefreshSMIMEKeysJob; + } + + QGpgME::RefreshOpenPGPKeysJob *refreshOpenPGPKeysJob() const Q_DECL_OVERRIDE + { + if (mProtocol != GpgME::OpenPGP) { + return nullptr; } GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol); diff --git a/lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp b/lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp index 425b9bf7..36ea9a1b 100644 --- a/lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp +++ b/lang/qt/src/qgpgmerefreshopenpgpkeysjob.cpp @@ -80,7 +80,7 @@ QGpgMERefreshOpenPGPKeysJob::QGpgMERefreshOpenPGPKeysJob(Context *context) QGpgMERefreshOpenPGPKeysJob::~QGpgMERefreshOpenPGPKeysJob() = default; -static Error locate_external_keys(Context *ctx, const std::vector &keys) +static ImportResult locate_external_keys(Context *ctx, const std::vector &keys) { Context::KeyListModeSaver saver{ctx}; ctx->setKeyListMode(GpgME::LocateExternal); @@ -88,13 +88,14 @@ static Error locate_external_keys(Context *ctx, const std::vector &keys) const auto emails = toEmailAddresses(keys); std::vector dummy; auto job = std::unique_ptr{new QGpgMEKeyListJob{ctx}}; - const auto result = job->exec(emails, false, dummy); + (void) job->exec(emails, false, dummy); + const auto result = ctx->importResult(); job.release(); - return result.error(); + return result; } -static Error receive_keys(Context *ctx, const std::vector &keys) +static ImportResult receive_keys(Context *ctx, const std::vector &keys) { const auto fprs = toFingerprints(keys); @@ -102,25 +103,22 @@ static Error receive_keys(Context *ctx, const std::vector &keys) const auto result = job->exec(fprs); job.release(); - return result.error(); + return result; } static QGpgMERefreshOpenPGPKeysJob::result_type refresh_keys(Context *ctx, const std::vector &keys) { - Error err; + ImportResult result; - err = locate_external_keys(ctx, keys); - if (!err) { - err = receive_keys(ctx, keys); + result = locate_external_keys(ctx, keys); + if (!result.error()) { + const auto res2 = receive_keys(ctx, keys); + if (!res2.error()) { + result.mergeWith(res2); + } } - return std::make_tuple(err, /*err ? WKDLookupResult{pattern, err} : result,*/ QString{}, Error{}); -} - -GpgME::Error QGpgMERefreshOpenPGPKeysJob::start(const QStringList &patterns) -{ - Q_UNUSED(patterns); - return GpgME::Error::fromCode(GPG_ERR_NOT_IMPLEMENTED); + return std::make_tuple(result, QString{}, Error{}); } GpgME::Error QGpgMERefreshOpenPGPKeysJob::start(const std::vector &keys) diff --git a/lang/qt/src/qgpgmerefreshopenpgpkeysjob.h b/lang/qt/src/qgpgmerefreshopenpgpkeysjob.h index 3ccfb5cf..be322e41 100644 --- a/lang/qt/src/qgpgmerefreshopenpgpkeysjob.h +++ b/lang/qt/src/qgpgmerefreshopenpgpkeysjob.h @@ -34,17 +34,23 @@ #ifndef __QGPGME_QGPGMEREFRESHOPENPGPKEYSJOB_H__ #define __QGPGME_QGPGMEREFRESHOPENPGPKEYSJOB_H__ -#include "refreshkeysjob.h" +#include "refreshopenpgpkeysjob.h" #include "threadedjobmixin.h" +#ifdef BUILDING_QGPGME +# include "importresult.h" +#else +# include +#endif + namespace QGpgME { class QGpgMERefreshOpenPGPKeysJob #ifdef Q_MOC_RUN - : public RefreshKeysJob + : public RefreshOpenPGPKeysJob #else - : public _detail::ThreadedJobMixin + : public _detail::ThreadedJobMixin> #endif { Q_OBJECT @@ -56,9 +62,6 @@ public: explicit QGpgMERefreshOpenPGPKeysJob(GpgME::Context *context); ~QGpgMERefreshOpenPGPKeysJob() override; - /** This overload is not implemented. Use the other overload. */ - GpgME::Error start(const QStringList &patterns) override; - GpgME::Error start(const std::vector &keys) override; }; diff --git a/lang/qt/src/refreshopenpgpkeysjob.h b/lang/qt/src/refreshopenpgpkeysjob.h new file mode 100644 index 00000000..74233b61 --- /dev/null +++ b/lang/qt/src/refreshopenpgpkeysjob.h @@ -0,0 +1,67 @@ +/* + refreshopenpgpkeysjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2022 g10 Code GmbH + Software engineering by Ingo Klöcker + + QGpgME is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + QGpgME is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifndef __KLEO_REFRESHOPENPGPKEYSJOB_H__ +#define __KLEO_REFRESHOPENPGPKEYSJOB_H__ + +#include "abstractimportjob.h" +#include "qgpgme_export.h" + +#include + +namespace GpgME +{ +class Error; +class Key; +} + +namespace QGpgME +{ + +class QGPGME_EXPORT RefreshOpenPGPKeysJob : public AbstractImportJob +{ + Q_OBJECT +protected: + explicit RefreshOpenPGPKeysJob(QObject *parent); +public: + ~RefreshOpenPGPKeysJob() override; + + /** + Starts a refresh of the \a keys. + */ + virtual GpgME::Error start(const std::vector &keys) = 0; +}; + +} + +#endif // __KLEO_REFRESHOPENPGPKEYSJOB_H__ diff --git a/lang/qt/tests/run-refreshkeysjob.cpp b/lang/qt/tests/run-refreshkeysjob.cpp index a9cf5e61..4c8f4086 100644 --- a/lang/qt/tests/run-refreshkeysjob.cpp +++ b/lang/qt/tests/run-refreshkeysjob.cpp @@ -36,11 +36,13 @@ #include #include +#include #include #include #include +#include #include @@ -117,21 +119,36 @@ int main(int argc, char **argv) auto key = openPGPKey.key.isNull() ? smimeKey.key : openPGPKey.key; std::cout << "Refreshing " << displayName(key.protocol()) << " key " << key.userID(0).id() << std::endl; - auto jobFactory = key.protocol() == GpgME::OpenPGP ? QGpgME::openpgp() : QGpgME::smime(); - auto job = jobFactory->refreshKeysJob(); - if (!job) { - std::cerr << "Error: Could not create job to refresh " << displayName(key.protocol()) << " key" << std::endl; - return 1; - } - QObject::connect(job, &QGpgME::RefreshKeysJob::result, &app, [](const GpgME::Error &err, const QString &, const GpgME::Error &) { - std::cout << "Result: " << err.asString() << std::endl; - qApp->quit(); - }); - - const auto err = job->start({key}); - if (err) { - std::cerr << "Error: " << err.asString() << std::endl; - return 1; + if (key.protocol() == GpgME::OpenPGP) { + auto job = QGpgME::openpgp()->refreshOpenPGPKeysJob(); + if (!job) { + std::cerr << "Error: Could not create job to refresh OpenPGP key" << std::endl; + return 1; + } + QObject::connect(job, &QGpgME::RefreshOpenPGPKeysJob::result, &app, [](const GpgME::ImportResult &result, const QString &, const GpgME::Error &) { + std::cout << "Result: " << result << std::endl; + qApp->quit(); + }); + const auto err = job->start({key}); + if (err) { + std::cerr << "Error: " << err.asString() << std::endl; + return 1; + } + } else { + auto job = QGpgME::smime()->refreshKeysJob(); + if (!job) { + std::cerr << "Error: Could not create job to refresh S/MIME key" << std::endl; + return 1; + } + QObject::connect(job, &QGpgME::RefreshKeysJob::result, &app, [](const GpgME::Error &err, const QString &, const GpgME::Error &) { + std::cout << "Result: " << err.asString() << std::endl; + qApp->quit(); + }); + const auto err = job->start({key}); + if (err) { + std::cerr << "Error: " << err.asString() << std::endl; + return 1; + } } return app.exec();