From 2ad36f71144731f847c89b1f1e91f21c215cffa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Mon, 21 Aug 2023 16:01:37 +0200 Subject: [PATCH] qt: Add job for refreshing OpenPGP keys via WKD * lang/qt/src/wkdrefreshjob.cpp, lang/qt/src/wkdrefreshjob.h, lang/qt/src/wkdrefreshjob_p.h, lang/qt/src/qgpgmewkdrefreshjob.cpp, lang/qt/src/qgpgmewkdrefreshjob.h: New. * lang/qt/src/protocol.h (class Protocol): Add pure virtual member function wkdRefreshJob * lang/qt/src/protocol_p.h (Protocol::wkdRefreshJob): ... and implement it. * lang/qt/src/Makefile.am: Update accordingly. * lang/qt/tests/run-wkdrefreshjob.cpp: New. * lang/qt/tests/Makefile.am: Add new test runner. -- This job allows updating keys via WKD. Only user IDs that were originally retrieved via WKD (i.e. which have origin WKD) are considered. GnuPG-bug-id: 6672 --- NEWS | 6 ++ lang/qt/src/Makefile.am | 12 ++- lang/qt/src/protocol.h | 3 + lang/qt/src/protocol_p.h | 12 +++ lang/qt/src/qgpgmewkdrefreshjob.cpp | 147 ++++++++++++++++++++++++++++ lang/qt/src/qgpgmewkdrefreshjob.h | 64 ++++++++++++ lang/qt/src/wkdrefreshjob.cpp | 57 +++++++++++ lang/qt/src/wkdrefreshjob.h | 71 ++++++++++++++ lang/qt/src/wkdrefreshjob_p.h | 51 ++++++++++ lang/qt/tests/Makefile.am | 4 +- lang/qt/tests/run-wkdrefreshjob.cpp | 121 +++++++++++++++++++++++ 11 files changed, 545 insertions(+), 3 deletions(-) create mode 100644 lang/qt/src/qgpgmewkdrefreshjob.cpp create mode 100644 lang/qt/src/qgpgmewkdrefreshjob.h create mode 100644 lang/qt/src/wkdrefreshjob.cpp create mode 100644 lang/qt/src/wkdrefreshjob.h create mode 100644 lang/qt/src/wkdrefreshjob_p.h create mode 100644 lang/qt/tests/run-wkdrefreshjob.cpp diff --git a/NEWS b/NEWS index 60810787..7f38bee7 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ Noteworthy changes in version 1.22.1 (unreleased) ------------------------------------------------- + * qt: Support refreshing keys via WKD. [T6672] + + * Interface changes relative to the 1.22.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + qt: Protocol::wkdRefreshJob NEW. + qt: WKDRefreshJob NEW. Noteworthy changes in version 1.22.0 (2023-08-21) ------------------------------------------------- diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 3b3f1e80..b6929f26 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -56,6 +56,7 @@ qgpgme_sources = \ qgpgmesignencryptarchivejob.cpp \ qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \ qgpgmeverifyopaquejob.cpp qgpgmewkdlookupjob.cpp threadedjobmixin.cpp \ + qgpgmewkdrefreshjob.cpp \ qgpgmekeyformailboxjob.cpp qgpgme_debug.cpp \ qgpgmetofupolicyjob.cpp qgpgmequickjob.cpp \ defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp \ @@ -64,7 +65,8 @@ qgpgme_sources = \ signencryptjob.cpp \ signencryptarchivejob.cpp \ dn.cpp cryptoconfig.cpp wkdlookupresult.cpp \ - util.cpp + util.cpp \ + wkdrefreshjob.cpp # If you add one here make sure that you also add one in camelcase qgpgme_headers= \ @@ -115,6 +117,7 @@ qgpgme_headers= \ tofupolicyjob.h \ wkdlookupjob.h \ wkdlookupresult.h \ + wkdrefreshjob.h \ wkspublishjob.h \ gpgcardjob.h \ dn.h @@ -166,6 +169,7 @@ camelcase_headers= \ DefaultKeyGenerationJob \ WKDLookupJob \ WKDLookupResult \ + WKDRefreshJob \ WKSPublishJob \ TofuPolicyJob \ GpgCardJob @@ -211,6 +215,7 @@ private_qgpgme_headers = \ qgpgmeverifydetachedjob.h \ qgpgmeverifyopaquejob.h \ qgpgmewkdlookupjob.h \ + qgpgmewkdrefreshjob.h \ qgpgmekeyformailboxjob.h \ qgpgmewkspublishjob.h \ qgpgmetofupolicyjob.h \ @@ -220,7 +225,8 @@ private_qgpgme_headers = \ signencryptjob_p.h \ signencryptarchivejob_p.h \ threadedjobmixin.h \ - util.h + util.h \ + wkdrefreshjob_p.h qgpgme_moc_sources = \ abstractimportjob.moc \ @@ -275,6 +281,7 @@ qgpgme_moc_sources = \ qgpgmeverifydetachedjob.moc \ qgpgmeverifyopaquejob.moc \ qgpgmewkdlookupjob.moc \ + qgpgmewkdrefreshjob.moc \ qgpgmewkspublishjob.moc \ tofupolicyjob.moc \ qgpgmetofupolicyjob.moc \ @@ -291,6 +298,7 @@ qgpgme_moc_sources = \ verifydetachedjob.moc \ verifyopaquejob.moc \ wkdlookupjob.moc \ + wkdrefreshjob.moc \ keyformailboxjob.moc \ wkspublishjob.moc \ qgpgmekeyformailboxjob.moc \ diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index cbd93877..74fb921d 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -77,6 +77,7 @@ class GpgCardJob; class ReceiveKeysJob; class RevokeKeyJob; class SetPrimaryUserIDJob; +class WKDRefreshJob; /** The main entry point for QGpgME Comes in OpenPGP and SMIME(CMS) flavors. * @@ -198,6 +199,8 @@ public: virtual SignArchiveJob *signArchiveJob(bool armor = false) const = 0; virtual SignEncryptArchiveJob *signEncryptArchiveJob(bool armor = false) const = 0; virtual DecryptVerifyArchiveJob *decryptVerifyArchiveJob() const = 0; + + virtual WKDRefreshJob *wkdRefreshJob() 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 fcb2b30a..b34b7a37 100644 --- a/lang/qt/src/protocol_p.h +++ b/lang/qt/src/protocol_p.h @@ -71,6 +71,7 @@ #include "qgpgmereceivekeysjob.h" #include "qgpgmerevokekeyjob.h" #include "qgpgmesetprimaryuseridjob.h" +#include "qgpgmewkdrefreshjob.h" namespace { @@ -557,6 +558,17 @@ public: } return nullptr; } + + QGpgME::WKDRefreshJob *wkdRefreshJob() const override + { + if (mProtocol != GpgME::OpenPGP) { + return nullptr; + } + if (auto context = GpgME::Context::createForProtocol(mProtocol)) { + return new QGpgME::QGpgMEWKDRefreshJob{context}; + } + return nullptr; + } }; } diff --git a/lang/qt/src/qgpgmewkdrefreshjob.cpp b/lang/qt/src/qgpgmewkdrefreshjob.cpp new file mode 100644 index 00000000..8bad1ef1 --- /dev/null +++ b/lang/qt/src/qgpgmewkdrefreshjob.cpp @@ -0,0 +1,147 @@ +/* + qgpgmewkdrefreshjob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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. +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "qgpgmewkdrefreshjob.h" + +#include "debug.h" +#include "qgpgme_debug.h" +#include "qgpgmekeylistjob.h" +#include "wkdrefreshjob_p.h" + +#include + +#include + +using namespace QGpgME; +using namespace GpgME; + +namespace +{ + +class QGpgMEWKDRefreshJobPrivate : public WKDRefreshJobPrivate +{ + QGpgMEWKDRefreshJob *q = nullptr; + +public: + QGpgMEWKDRefreshJobPrivate(QGpgMEWKDRefreshJob *qq) + : q{qq} + { + } + + ~QGpgMEWKDRefreshJobPrivate() override = default; + +private: + GpgME::Error startIt() override; + + void startNow() override + { + q->run(); + } +}; + +static QStringList toEmailAddressesOriginatingFromWKD(const std::vector &keys) +{ + const QStringList emails = std::accumulate(keys.begin(), keys.end(), QStringList{}, [](QStringList &emails, const Key &key) { + const auto userIDs = key.userIDs(); + emails = std::accumulate(std::begin(userIDs), std::end(userIDs), emails, [](QStringList &emails, const UserID &userID) { + if (!userID.isRevoked() && !userID.addrSpec().empty() && userID.origin() == Key::OriginWKD) { + emails.push_back(QString::fromStdString(userID.addrSpec())); + } + return emails; + }); + return emails; + }); + return emails; +} + +} + +QGpgMEWKDRefreshJob::QGpgMEWKDRefreshJob(Context *context) + : mixin_type{context} +{ + setJobPrivate(this, std::unique_ptr{new QGpgMEWKDRefreshJobPrivate{this}}); + lateInitialization(); +} + +QGpgMEWKDRefreshJob::~QGpgMEWKDRefreshJob() = default; + +static ImportResult locate_external_keys(Context *ctx, const std::vector &keys) +{ + const auto emails = toEmailAddressesOriginatingFromWKD(keys); + qCDebug(QGPGME_LOG) << __func__ << "locating external keys for" << emails; + if (emails.empty()) { + return ImportResult{}; + } + + Context::KeyListModeSaver saver{ctx}; + ctx->setKeyListMode(GpgME::LocateExternal); + ctx->setFlag("auto-key-locate", "clear,wkd"); + std::vector dummy; + auto job = std::unique_ptr{new QGpgMEKeyListJob{ctx}}; + (void) job->exec(emails, false, dummy); + qCDebug(QGPGME_LOG) << __func__ << "number of keys:" << dummy.size(); + std::for_each(dummy.cbegin(), dummy.cend(), [](const Key &k) { + qCDebug(QGPGME_LOG) << __func__ << toLogString(k).c_str(); + }); + const auto result = ctx->importResult(); + qCDebug(QGPGME_LOG) << __func__ << "result:" << toLogString(result).c_str(); + job.release(); + + return result; +} + +static QGpgMEWKDRefreshJob::result_type refresh_keys(Context *ctx, const std::vector &keys) +{ + const auto result = locate_external_keys(ctx, keys); + + return std::make_tuple(result, QString{}, Error{}); +} + +GpgME::Error QGpgMEWKDRefreshJobPrivate::startIt() +{ + if (m_keys.empty()) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + q->run([=](Context *ctx) { + return refresh_keys(ctx, m_keys); + }); + + return {}; +} + +#include "qgpgmewkdrefreshjob.moc" diff --git a/lang/qt/src/qgpgmewkdrefreshjob.h b/lang/qt/src/qgpgmewkdrefreshjob.h new file mode 100644 index 00000000..1b775aed --- /dev/null +++ b/lang/qt/src/qgpgmewkdrefreshjob.h @@ -0,0 +1,64 @@ +/* + qgpgmewkdrefreshjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 __QGPGME_QGPGMEWKDREFRESHJOB_H__ +#define __QGPGME_QGPGMEWKDREFRESHJOB_H__ + +#include "threadedjobmixin.h" +#include "wkdrefreshjob.h" + +#include + +namespace QGpgME +{ + +class QGpgMEWKDRefreshJob +#ifdef Q_MOC_RUN + : public WKDRefreshJob +#else + : public _detail::ThreadedJobMixin> +#endif +{ + Q_OBJECT +#ifdef Q_MOC_RUN +public Q_SLOTS: + void slotFinished(); +#endif +public: + explicit QGpgMEWKDRefreshJob(GpgME::Context *context); + ~QGpgMEWKDRefreshJob() override; +}; + +} + +#endif // __QGPGME_QGPGMEWKDREFRESHJOB_H__ diff --git a/lang/qt/src/wkdrefreshjob.cpp b/lang/qt/src/wkdrefreshjob.cpp new file mode 100644 index 00000000..37b990c8 --- /dev/null +++ b/lang/qt/src/wkdrefreshjob.cpp @@ -0,0 +1,57 @@ +/* + wkdrefreshjob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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. +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "wkdrefreshjob.h" +#include "wkdrefreshjob_p.h" + +using namespace QGpgME; + +WKDRefreshJob::WKDRefreshJob(QObject *parent) + : AbstractImportJob{parent} +{ +} + +WKDRefreshJob::~WKDRefreshJob() = default; + +GpgME::Error WKDRefreshJob::start(const std::vector &keys) +{ + auto d = jobPrivate(this); + d->m_keys = keys; + return d->startIt(); +} + +#include "wkdrefreshjob.moc" diff --git a/lang/qt/src/wkdrefreshjob.h b/lang/qt/src/wkdrefreshjob.h new file mode 100644 index 00000000..c3aec65f --- /dev/null +++ b/lang/qt/src/wkdrefreshjob.h @@ -0,0 +1,71 @@ +/* + wkdrefreshjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 __QGPGME_WKDREFRESHJOB_H__ +#define __QGPGME_WKDREFRESHJOB_H__ + +#include "abstractimportjob.h" +#include "qgpgme_export.h" + +#include + +namespace GpgME +{ +class Error; +class Key; +} + +namespace QGpgME +{ + +/** + * This job refreshes OpenPGP keys via WKD. Only user IDs that have WKD set as + * origin are used for the WKD lookup. Revoked user IDs are ignored. + */ +class QGPGME_EXPORT WKDRefreshJob : public AbstractImportJob +{ + Q_OBJECT +protected: + explicit WKDRefreshJob(QObject *parent); +public: + ~WKDRefreshJob() override; + + /** + * Starts a refresh of the \a keys. + */ + GpgME::Error start(const std::vector &keys); +}; + +} + +#endif // __QGPGME_WKDREFRESHJOB_H__ diff --git a/lang/qt/src/wkdrefreshjob_p.h b/lang/qt/src/wkdrefreshjob_p.h new file mode 100644 index 00000000..377350f3 --- /dev/null +++ b/lang/qt/src/wkdrefreshjob_p.h @@ -0,0 +1,51 @@ +/* + wkdrefreshjob_p.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 __QGPGME_WKDREFRESHJOB_P_H__ +#define __QGPGME_WKDREFRESHJOB_P_H__ + +#include "job_p.h" + +#include + +namespace QGpgME +{ + +struct WKDRefreshJobPrivate : public JobPrivate +{ + std::vector m_keys; +}; + +} + +#endif // __QGPGME_WKDREFRESHJOB_P_H__ diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am index d9713d90..32ad6466 100644 --- a/lang/qt/tests/Makefile.am +++ b/lang/qt/tests/Makefile.am @@ -97,6 +97,7 @@ run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp run_receivekeysjob_SOURCES = run-receivekeysjob.cpp run_refreshkeysjob_SOURCES = run-refreshkeysjob.cpp run_signarchivejob_SOURCES = run-signarchivejob.cpp +run_wkdrefreshjob_SOURCES = run-wkdrefreshjob.cpp nodist_t_keylist_SOURCES = $(moc_files) @@ -112,7 +113,8 @@ noinst_PROGRAMS = \ run-decryptverifyarchivejob \ run-encryptarchivejob \ run-importjob run-exportjob run-receivekeysjob run-refreshkeysjob \ - run-signarchivejob + run-signarchivejob \ + run-wkdrefreshjob CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ diff --git a/lang/qt/tests/run-wkdrefreshjob.cpp b/lang/qt/tests/run-wkdrefreshjob.cpp new file mode 100644 index 00000000..757ee899 --- /dev/null +++ b/lang/qt/tests/run-wkdrefreshjob.cpp @@ -0,0 +1,121 @@ +/* + run-wkdrefreshjob.cpp + + This file is part of QGpgME's test suite. + Copyright (c) 2023 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. +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#include +#include + +#include +#include + +#include + +using namespace GpgME; + +std::ostream &operator<<(std::ostream &os, const QString &s) +{ + return os << s.toLocal8Bit().constData(); +} + +Key getOpenPGPKey(const QString &keyId, Error &err) +{ + Key key; + + auto ctx = Context::create(GpgME::OpenPGP); + if (!ctx) { + err = Error::fromCode(GPG_ERR_GENERAL); + return key; + } + + key = ctx->key(keyId.toLatin1().constData(), err); + if (err.code() == GPG_ERR_EOF) { + err = Error{}; + } + return key; +} + +int main(int argc, char **argv) +{ + GpgME::initializeLibrary(); + + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " KEYID" << std::endl; + return 1; + } + + QCoreApplication app{argc, argv}; + const auto keyId = qApp->arguments().last(); + + Error err; + const auto key = getOpenPGPKey(keyId, err); + if (err.code() == GPG_ERR_AMBIGUOUS_NAME) { + std::cerr << "Error: Multiple OpenPGP keys matching '" << keyId << "' found" << std::endl; + return 1; + } + if (key.isNull()) { + std::cerr << "Error: No OpenPGP key matching '" << keyId << "' found" << std::endl; + return 1; + } + if (err) { + std::cerr << "Error while getting OpenPGP key: " << err.asString() << std::endl; + return 1; + } + std::cout << "Refreshing OpenPGP key " << key.userID(0).id() << std::endl; + + auto job = QGpgME::openpgp()->wkdRefreshJob(); + if (!job) { + std::cerr << "Error: Could not create job to refresh OpenPGP key" << std::endl; + return 1; + } + QObject::connect(job, &QGpgME::WKDRefreshJob::result, &app, [](const GpgME::ImportResult &result, const QString &, const GpgME::Error &) { + if (result.isNull()) { + std::cout << "Empty result. Lookup via WKD failed or no user ID was originally retrieved via WKD." << std::endl; + } else { + std::cout << "Result: " << result << std::endl; + } + qApp->quit(); + }); + err = job->start({key}); + if (err) { + std::cerr << "Error: " << err.asString() << std::endl; + return 1; + } + + return app.exec(); +}