Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package qgpgme for openSUSE:Factory checked in at 2026-08-02 23:13:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/qgpgme (Old) and /work/SRC/openSUSE:Factory/.qgpgme.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "qgpgme" Sun Aug 2 23:13:48 2026 rev:4 rq:1369101 version:2.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/qgpgme/qgpgme.changes 2026-06-01 17:58:54.253628121 +0200 +++ /work/SRC/openSUSE:Factory/.qgpgme.new.16738/qgpgme.changes 2026-08-02 23:14:24.888255300 +0200 @@ -1,0 +2,7 @@ +Fri Jul 31 08:59:02 UTC 2026 - Andreas Stieger <[email protected]> + +- Update to 2.2.0: + * Add job for querying Active Directory + * Don't start dirmngr for WKD lookup if it is disabled for gpg + +------------------------------------------------------------------- Old: ---- qgpgme-2.1.0.tar.xz qgpgme-2.1.0.tar.xz.sig New: ---- qgpgme-2.2.0.tar.xz qgpgme-2.2.0.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ qgpgme.spec ++++++ --- /var/tmp/diff_new_pack.LdYxrE/_old 2026-08-02 23:14:25.508276582 +0200 +++ /var/tmp/diff_new_pack.LdYxrE/_new 2026-08-02 23:14:25.512276720 +0200 @@ -17,13 +17,14 @@ %define sover 15 -%if 0%{?suse_version} >= 1600 +%bcond_without qt5 +%if 0%{?suse_version} > 1600 %bcond_without qt6 %else %bcond_with qt6 %endif Name: qgpgme -Version: 2.1.0 +Version: 2.2.0 Release: 0 Summary: Qt API bindings/wrapper for GPGME License: GPL-2.0-or-later @@ -36,13 +37,15 @@ BuildRequires: c++_compiler BuildRequires: cmake BuildRequires: pkgconfig -BuildRequires: cmake(Gpgmepp) >= 2.0.0 -BuildRequires: cmake(Qt5Core) >= 5.15.0 +BuildRequires: cmake(Gpgmepp) >= 2.1.0 BuildRequires: pkgconfig(gpg-error) >= 1.47 -BuildRequires: pkgconfig(gpgme) >= 2.0.0 +BuildRequires: pkgconfig(gpgme) >= 2.1.0 +%if %{with qt5} +BuildRequires: cmake(Qt5Core) >= 5.15.0 +%endif %if %{with qt6} BuildRequires: cmake(Qt6Core) >= 6.5.0 -BuildRequires: cmake(Qt6CoreTools) >= 6.9.1 +BuildRequires: cmake(Qt6CoreTools) >= 6.11.1 BuildRequires: cmake(Qt6Test) %endif %if 0%{?suse_version} < 1600 @@ -52,6 +55,7 @@ %description QGpgme provides a very high level Qt API around GpgMEpp. +%if %{with qt5} %package -n libqgpgme%{sover} Summary: Qt5 API bindings/wrapper for GPGME @@ -59,6 +63,7 @@ QGpgme provides a very high level Qt API around GpgMEpp. This package contains the shared library built for Qt5. +%endif %if %{with qt6} %package -n libqgpgmeqt6-%{sover} @@ -70,21 +75,23 @@ This package contains the shared library built for Qt6. %endif +%if %{with qt5} %package -n libqgpgme-devel Summary: Development files for %{name} (Qt5) Requires: libqgpgme%{sover} = %{version} -Requires: cmake(Gpgmepp) >= 2.0.0 +Requires: cmake(Gpgmepp) >= 2.1.0 %description -n libqgpgme-devel QGpgme provides a very high level Qt API around GpgMEpp. This package contains the files needed to build using %{name} and Qt5. +%endif %if %{with qt6} %package -n libqgpgmeqt6-devel Summary: Development files for %{name} (Qt6) Requires: libqgpgmeqt6-%{sover} = %{version} -Requires: cmake(Gpgmepp) >= 2.0.0 +Requires: cmake(Gpgmepp) >= 2.1.0 %description -n libqgpgmeqt6-devel QGpgme provides a very high level Qt API around GpgMEpp. @@ -100,9 +107,15 @@ export CXX=g++-12 %endif %cmake \ +%if %{with qt5} -DBUILD_WITH_QT5:BOOL=ON \ +%else + -DBUILD_WITH_QT5:BOOL=OFF \ +%endif %if %{with qt6} -DBUILD_WITH_QT6:BOOL=ON \ +%else + -DBUILD_WITH_QT6:BOOL=OFF \ %endif -DBUILD_TESTING:BOOL=ON \ %{nil} @@ -114,14 +127,18 @@ %check %ctest +%if %{with qt5} %ldconfig_scriptlets -n libqgpgme%{sover} +%endif %if %{with qt6} %ldconfig_scriptlets -n libqgpgmeqt6-%{sover} %endif +%if %{with qt5} %files -n libqgpgme%{sover} %license COPYING %{_libdir}/libqgpgme.so.%{sover}{,.*} +%endif %if %{with qt6} %files -n libqgpgmeqt6-%{sover} @@ -129,12 +146,14 @@ %{_libdir}/libqgpgmeqt6.so.%{sover}{,.*} %endif +%if %{with qt5} %files -n libqgpgme-devel %license COPYING %doc ChangeLog NEWS README VERSION %{_libdir}/libqgpgme.so %{_includedir}/qgpgme-qt5 %{_libdir}/cmake/QGpgme +%endif %if %{with qt6} %files -n libqgpgmeqt6-devel ++++++ qgpgme-2.1.0.tar.xz -> qgpgme-2.2.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/CMakeLists.txt new/qgpgme-2.2.0/CMakeLists.txt --- old/qgpgme-2.1.0/CMakeLists.txt 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/CMakeLists.txt 2026-07-20 15:07:38.000000000 +0200 @@ -21,7 +21,7 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) -set(FULL_VERSION "2.1.0") +set(FULL_VERSION "2.2.0") string(REGEX MATCH "^[0-9]+.[0-9]+.[0-9]+" cmake_compat_version ${FULL_VERSION}) project(qgpgme VERSION ${cmake_compat_version}) @@ -35,14 +35,14 @@ # (Interfaces added/removed/changed: CURRENT++, REVISION=0) # (Interfaces added: AGE++) # (Interfaces removed: AGE=0) -set(LIBQGPGME_LT_CURRENT "23") -set(LIBQGPGME_LT_AGE "8") +set(LIBQGPGME_LT_CURRENT "24") +set(LIBQGPGME_LT_AGE "9") set(LIBQGPGME_LT_REVISION "0") math(EXPR LIBQGPGME_SOVERSION "${LIBQGPGME_LT_CURRENT} - ${LIBQGPGME_LT_AGE}") set(GPG_ERROR_REQUIRED_VERSION "1.47") -set(GPGME_REQUIRED_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.0") -set(GPGMEPP_REQUIRED_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.0") +set(GPGME_REQUIRED_VERSION "2.1.0") +set(GPGMEPP_REQUIRED_VERSION "2.1.0") set(QT5_REQUIRED_VERSION "5.15.0") set(QT6_REQUIRED_VERSION "6.5.0") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/ChangeLog new/qgpgme-2.2.0/ChangeLog --- old/qgpgme-2.1.0/ChangeLog 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/ChangeLog 2026-07-20 15:07:38.000000000 +0200 @@ -1,3 +1,45 @@ +2026-07-20 Ingo Klöcker <[email protected]> + + Release 2.2.0. + + commit 447c4a7665c9b3467b489d8b3e73513fb1eff4a4 + + +2026-06-24 Ingo Klöcker <[email protected]> + + Don't start dirmngr for WKD lookup if it is disabled for gpg. + + commit d764c5c57973fb452726024d1ef8634e1856e5a0 + * src/qgpgmewkdlookupjob.cpp (startDirmngr): Check disable-dirmngr + option of gpg. + + Don't start dirmngr for AD query if it is disabled for gpg and gpgsm. + + commit 82ad47a35d0f4e47a7a9f958a519b0230d21524e + * src/qgpgmeadqueryjob.cpp (startDirmngr): Check disable-dirmngr + option of gpg and gpgsm. + +2026-06-17 Ingo Klöcker <[email protected]> + + Add job for querying Active Directory. + + commit 905e3851170d362261f1f6b6c04767aa23332baa + * src/CMakeLists.txt: Add new files. + * src/adqueryjob.cpp, src/adqueryjob.h, src/adqueryjob_p.h, + src/adqueryresult.cpp, src/adqueryresult.h, src/qgpgmeadqueryjob.cpp, + src/qgpgmeadqueryjob.h: New. + * src/protocol.h (class Protocol): Add pure virtual member function + adQueryJob + * src/protocol_p.h (Protocol::adQueryJob): ... and implement it. + * src/qt6compat_p.h (operator<<): Add QDebug stream operator for + std::string for Qt 5 and older Qt 6. + + * tests/CMakeLists.txt: Add new test runner run-adqueryjob. + * tests/run-adqueryjob.cpp: New. + + Add helper for splitting a std::string_view. + + commit 47af4f6a344ea8ee1fb69ef447979894b58fb0f6 + * src/util.h (_qgpgme::split): New. + + * tests/CMakeLists.txt: Add new test. + * tests/t-util.cpp: New. + 2026-05-18 Werner Koch <[email protected]> Release 2.1.0. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/NEWS new/qgpgme-2.2.0/NEWS --- old/qgpgme-2.1.0/NEWS 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/NEWS 2026-07-20 15:07:38.000000000 +0200 @@ -1,3 +1,21 @@ +Noteworthy changes in version 2.2.0 (2026-07-20) [C24/A9/R0] +------------------------------------------------ + + * Add job for querying Active Directory. [T6094] + + * Don't start dirmngr for WKD lookup if it is disabled for gpg. [T8304] + + * Interface changes relative to the 2.1.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ADQueryJob NEW. + ADQueryOption NEW. + ADQueryOptions NEW. + ADQueryResult NEW. + Protocol::adQueryJob NEW. + + Release-info: https://dev.gnupg.org/T8360 + + Noteworthy changes in version 2.1.0 (2026-05-18) [C23/A8/R0] ------------------------------------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/VERSION new/qgpgme-2.2.0/VERSION --- old/qgpgme-2.1.0/VERSION 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/VERSION 2026-07-20 15:07:38.000000000 +0200 @@ -1,2 +1,2 @@ -2.1.0 -02184c928f555efc6b18b6ec08379e15ddd68894 +2.2.0 +447c4a7665c9b3467b489d8b3e73513fb1eff4a4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/CMakeLists.txt new/qgpgme-2.2.0/src/CMakeLists.txt --- old/qgpgme-2.1.0/src/CMakeLists.txt 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/CMakeLists.txt 2026-07-20 15:07:38.000000000 +0200 @@ -36,6 +36,8 @@ abstractimportjob.cpp addexistingsubkeyjob.cpp adduseridjob.cpp + adqueryjob.cpp + adqueryresult.cpp changeexpiryjob.cpp changeownertrustjob.cpp changepasswdjob.cpp @@ -66,6 +68,7 @@ qgpgme_debug.cpp qgpgmeaddexistingsubkeyjob.cpp qgpgmeadduseridjob.cpp + qgpgmeadqueryjob.cpp qgpgmebackend.cpp qgpgmechangeexpiryjob.cpp qgpgmechangeownertrustjob.cpp @@ -140,6 +143,7 @@ protocol_p.h qgpgmeaddexistingsubkeyjob.h qgpgmeadduseridjob.h + qgpgmeadqueryjob.h qgpgmebackend.h qgpgmechangeexpiryjob.h qgpgmechangeownertrustjob.h @@ -197,6 +201,8 @@ AbstractImportJob AddExistingSubkeyJob AddUserIDJob + ADQueryJob + ADQueryResult ChangeExpiryJob ChangeOwnerTrustJob ChangePasswdJob diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/adqueryjob.cpp new/qgpgme-2.2.0/src/adqueryjob.cpp --- old/qgpgme-2.1.0/src/adqueryjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/adqueryjob.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,70 @@ +/* + adqueryjob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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 "adqueryjob.h" + +#include "adqueryjob_p.h" +#include "adqueryresult.h" + +using namespace QGpgME; + +ADQueryJob::ADQueryJob(std::unique_ptr<ADQueryJobPrivate> dd, QObject *parent) + : Job{std::move(dd), parent} +{ +} + +ADQueryJob::~ADQueryJob() = default; + +GpgME::Error ADQueryJob::start(const QString &filter, const QStringList &attributes, ADQueryOptions options) +{ + Q_D(ADQueryJob); + d->m_filter = filter; + d->m_attributes = attributes; + d->m_options = options; + return d->startIt(); +} + +ADQueryResult ADQueryJob::exec(const QString &filter, const QStringList &attributes, ADQueryOptions options) +{ + Q_D(ADQueryJob); + d->m_filter = filter; + d->m_attributes = attributes; + d->m_options = options; + return d->execIt(); +} + +#include "moc_adqueryjob.cpp" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/adqueryjob.h new/qgpgme-2.2.0/src/adqueryjob.h --- old/qgpgme-2.1.0/src/adqueryjob.h 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/adqueryjob.h 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,90 @@ +/* + adqueryjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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_ADQUERYJOB_H__ +#define __QGPGME_ADQUERYJOB_H__ + +#include "job.h" + +#include "qgpgme_export.h" + +class QString; + +namespace GpgME +{ +class Error; +} + +namespace QGpgME +{ + +enum class ADQueryOption { + Default = 0x00, + RootDSE = 0x01, + SubstituteVariables = 0x02, +}; +Q_DECLARE_FLAGS(ADQueryOptions, ADQueryOption); + +class ADQueryResult; + +class ADQueryJobPrivate; + +class QGPGME_EXPORT ADQueryJob : public Job +{ + Q_OBJECT +protected: + ADQueryJob(std::unique_ptr<ADQueryJobPrivate>, QObject *parent); + +public: + ~ADQueryJob() override; + + /** + * Starts an AD query with filter \a filter asking for the attributes \a attributes. + */ + GpgME::Error start(const QString &filter, const QStringList &attributes, ADQueryOptions options = ADQueryOption::Default); + + /** + * Runs an AD query with filter \a filter asking for the attributes \a attributes. + */ + ADQueryResult exec(const QString &filter, const QStringList &attributes, ADQueryOptions options = ADQueryOption::Default); + +Q_SIGNALS: + void result(const ADQueryResult &result, const QString &auditLogAsHtml = {}, const GpgME::Error &auditLogError = {}); + +private: + Q_DECLARE_PRIVATE(ADQueryJob) +}; + +} + +#endif // __QGPGME_ADQUERYJOB_H__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/adqueryjob_p.h new/qgpgme-2.2.0/src/adqueryjob_p.h --- old/qgpgme-2.1.0/src/adqueryjob_p.h 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/adqueryjob_p.h 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,58 @@ +/* + adqueryjob_p.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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_ADQUERYEJOB_P_H__ +#define __QGPGME_ADQUERYEJOB_P_H__ + +#include "adqueryjob.h" + +#include "job_p.h" + +namespace QGpgME +{ + +class ADQueryResult; + +class ADQueryJobPrivate : public JobPrivate +{ +public: + QString m_filter; + QStringList m_attributes; + ADQueryOptions m_options = ADQueryOption::Default; + + virtual ADQueryResult execIt() = 0; +}; + +} + +#endif // __QGPGME_ADQUERYEJOB_P_H__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/adqueryresult.cpp new/qgpgme-2.2.0/src/adqueryresult.cpp --- old/qgpgme-2.1.0/src/adqueryresult.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/adqueryresult.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,133 @@ +/* + adqueryresult.cpp - wraps the result of a ADQueryJob + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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 "adqueryresult.h" + +#include <iterator> +#include <ostream> + +using namespace QGpgME; +using namespace GpgME; + +class ADQueryResult::Private +{ +public: + QList<Attribute> attributes; + QString source; +}; + +ADQueryResult::ADQueryResult() = default; + +ADQueryResult::~ADQueryResult() = default; + +ADQueryResult::ADQueryResult(const Error &error) + : Result{error} + , d{new Private{{}, {}}} +{ +} + +ADQueryResult::ADQueryResult(const QList<Attribute> &attributes, const QString &source, const GpgME::Error &error) + : Result{error} + , d{new Private{attributes, source}} +{ +} + +ADQueryResult::ADQueryResult(const ADQueryResult &other) + : Result{other} +{ + if (other.d) { + d.reset(new Private{*other.d}); + } +} + +ADQueryResult &ADQueryResult::operator=(const ADQueryResult &other) +{ + auto tmp = other; + swap(tmp); + return *this; +} + +ADQueryResult::ADQueryResult(ADQueryResult &&other) = default; + +ADQueryResult &ADQueryResult::operator=(ADQueryResult &&other) = default; + +void ADQueryResult::swap(ADQueryResult &other) noexcept +{ + Result::swap(other); + std::swap(this->d, other.d); +} + +bool ADQueryResult::isNull() const +{ + return !d && !bool(error()); +} + +QList<ADQueryResult::Attribute> ADQueryResult::attributes() const +{ + return d ? d->attributes : QList<ADQueryResult::Attribute>{}; +} + +QString ADQueryResult::source() const +{ + return d ? d->source : QString{}; +} + +void QGpgME::swap(ADQueryResult &a, ADQueryResult &b) +{ + a.swap(b); +} + +std::ostream &QGpgME::operator<<(std::ostream &os, const ADQueryResult &result) +{ + os << "QGpgME::ADQueryResult("; + if (!result.isNull()) { + os << "\n source: " << result.source().toStdString() + << "\n attributes:\n"; + const auto attributes = result.attributes(); + std::copy(attributes.begin(), attributes.end(), + std::ostream_iterator<ADQueryResult::Attribute>(os, "\n")); + } + return os << ')'; +} + +std::ostream &QGpgME::operator<<(std::ostream &os, const ADQueryResult::Attribute &attribute) +{ + return os << "QGpgME::ADQueryResult::Attribute(" + << "\n name: " << attribute.name.toStdString() + << "\n value: " << attribute.value.toStdString() + << "\n)"; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/adqueryresult.h new/qgpgme-2.2.0/src/adqueryresult.h --- old/qgpgme-2.1.0/src/adqueryresult.h 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/adqueryresult.h 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,99 @@ +/* + adqueryresult.h - wraps the result of a ADQueryJob + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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_ADQUERYRESULT_H__ +#define __QGPGME_ADQUERYRESULT_H__ + +#include "qgpgme_export.h" + +#include <QList> +#include <QString> + +#include <gpgme++/result.h> + +#include <memory> + +namespace GpgME +{ +class Error; +} + +namespace QGpgME +{ + +class QGPGME_EXPORT ADQueryResult : public GpgME::Result +{ +public: + struct Attribute { + QString name; + QString value; + + Attribute(QString _name, QString _value) + : name(std::move(_name)) + , value(std::move(_value)) + { + } + }; + + ADQueryResult(); + ~ADQueryResult(); + + explicit ADQueryResult(const GpgME::Error &err); + explicit ADQueryResult(const QList<Attribute> &attributes, const QString &source, const GpgME::Error &err); + + ADQueryResult(const ADQueryResult &other); + ADQueryResult &operator=(const ADQueryResult &other); + + ADQueryResult(ADQueryResult &&other); + ADQueryResult &operator=(ADQueryResult &&other); + + void swap(ADQueryResult &other) noexcept; + + bool isNull() const; + + QList<Attribute> attributes() const; + QString source() const; + +private: + class Private; + std::unique_ptr<Private> d; +}; + +QGPGME_EXPORT void swap(ADQueryResult &a, ADQueryResult &b); + +QGPGME_EXPORT std::ostream &operator<<(std::ostream &os, const ADQueryResult &result); +QGPGME_EXPORT std::ostream &operator<<(std::ostream &os, const ADQueryResult::Attribute &result); + +} + +#endif // __QGPGME_ADQUERYRESULT_H__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/protocol.h new/qgpgme-2.2.0/src/protocol.h --- old/qgpgme-2.1.0/src/protocol.h 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/protocol.h 2026-07-20 15:07:38.000000000 +0200 @@ -41,6 +41,7 @@ namespace QGpgME { class AddExistingSubkeyJob; +class ADQueryJob; class CryptoConfig; class KeyListJob; class ListAllKeysJob; @@ -201,6 +202,8 @@ virtual DecryptVerifyArchiveJob *decryptVerifyArchiveJob() const = 0; virtual WKDRefreshJob *wkdRefreshJob() const = 0; + + virtual ADQueryJob *adQueryJob() const = 0; }; /** Obtain a reference to the OpenPGP Protocol. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/protocol_p.h new/qgpgme-2.2.0/src/protocol_p.h --- old/qgpgme-2.1.0/src/protocol_p.h 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/protocol_p.h 2026-07-20 15:07:38.000000000 +0200 @@ -37,6 +37,7 @@ #define __QGPGME_PROTOCOL_P_H__ #include "qgpgmenewcryptoconfig.h" +#include "qgpgmeadqueryjob.h" #include "qgpgmekeygenerationjob.h" #include "qgpgmekeylistjob.h" #include "qgpgmelistallkeysjob.h" @@ -566,6 +567,14 @@ } return nullptr; } + + QGpgME::ADQueryJob *adQueryJob() const override + { + if (auto context = GpgME::Context::createForEngine(GpgME::AssuanEngine)) { + return new QGpgME::QGpgMEADQueryJob{context.release()}; + } + return nullptr; + } }; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/qgpgmeadqueryjob.cpp new/qgpgme-2.2.0/src/qgpgmeadqueryjob.cpp --- old/qgpgme-2.1.0/src/qgpgmeadqueryjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/qgpgmeadqueryjob.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,256 @@ +/* + qgpgmeadqueryjob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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 "qgpgmeadqueryjob.h" + +#include "adqueryjob_p.h" +#include "cryptoconfig.h" +#include "debug.h" +#include "protocol.h" +#include "qgpgme_debug.h" +#include "qt6compat_p.h" +#include "util.h" + +#include <gpgme++/context.h> +#include <gpgme++/data.h> +#include <gpgme++/defaultassuantransaction.h> + +#include <gpg-error.h> + +using namespace QGpgME; +using namespace GpgME; +using namespace Qt::Literals; + +namespace QGpgME +{ + +class QGpgMEADQueryJobPrivate : public ADQueryJobPrivate +{ +public: + Q_DECLARE_PUBLIC(QGpgMEADQueryJob) + + QGpgMEADQueryJobPrivate() = default; + + ~QGpgMEADQueryJobPrivate() override = default; + +private: + QGpgMEADQueryJob::result_type runADQuery(Context *ctx, const QString &filter, const QStringList &attributes, ADQueryOptions options); + + GpgME::Error startIt() override; + + void startNow() override + { + Q_Q(QGpgMEADQueryJob); + q->run(); + } + + ADQueryResult execIt() override; +}; + +} + +QGpgMEADQueryJob::QGpgMEADQueryJob(Context *context) + : mixin_type{context} +{ + lateInitialization(); +} + +QGpgMEADQueryJob::~QGpgMEADQueryJob() = default; + +static GpgME::Error startDirmngr(Context *assuanCtx) +{ + // don't start dirmngr if it is disabled for gpg _and_ gpgsm + if (QGpgME::cryptoConfig()->entry("gpg", "disable-dirmngr")->boolValue() + && QGpgME::cryptoConfig()->entry("gpgsm", "disable-dirmngr")->boolValue()) { + return Error::fromCode(GPG_ERR_NO_DIRMNGR); + } + + Error err; + auto spawnCtx = std::unique_ptr<Context>{Context::createForEngine(SpawnEngine, &err)}; + if (err) { + qCDebug(QGPGME_LOG) << "Error: Failed to get context for spawn engine (" << err << ")"; + } + const auto gpgconfProgram = GpgME::dirInfo("gpgconf-name"); + // replace backslashes with forward slashes in homedir to work around bug T6833 + std::string homedir{GpgME::dirInfo("homedir")}; + std::replace(homedir.begin(), homedir.end(), '\\', '/'); + const char *argv[] = { + gpgconfProgram, + "--homedir", + homedir.c_str(), + "--launch", + "dirmngr", + NULL + }; + auto ignoreIO = Data{Data::null}; + if (!err) { + qCDebug(QGPGME_LOG) << "Starting dirmngr ..."; + err = spawnCtx->spawn(gpgconfProgram, argv, + ignoreIO, ignoreIO, ignoreIO, + Context::SpawnDetached); + } + + if (!err) { + // wait for socket to become available + int cnt = 0; + do { + ++cnt; + qCDebug(QGPGME_LOG) << "Waiting for dirmngr to start ..."; + QThread::msleep(250 * cnt); + err = assuanCtx->assuanTransact("GETINFO version"); + } while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5); + } + + return err; +} + +static GpgME::Error setUpDirmngrAssuanConnection(Context *ctx) +{ + Error err; + + const std::string dirmngrSocket = GpgME::dirInfo("dirmngr-socket"); + err = ctx->setEngineFileName(dirmngrSocket.c_str()); + + if (!err) { + err = ctx->setEngineHomeDirectory(""); + } + + if (!err) { + // try to connect to dirmngr + err = ctx->assuanTransact("GETINFO version"); + if (err.code() == GPG_ERR_ASS_CONNECT_FAILED) { + err = startDirmngr(ctx); + } + } + + return err; +} + +static QString _QStringFromStdStringView(std::string_view s) +{ + return s.empty() ? QString{} : QString::fromUtf8(s.data(), s.size()); +} + +static QList<QGpgME::ADQueryResult::Attribute> parse_query_result(const std::string &resultData) +{ + QList<QGpgME::ADQueryResult::Attribute> result; + + const auto lines = _qgpgme::split(resultData, '\n'); + for (auto line : lines) { + if (line.empty()) { + continue; + } + if (line.front() == ' ') { + // line starts with space -> continuation of last value + if (!result.empty()) { + result.back().value += _QStringFromStdStringView(line.substr(1)); + } + } else { + const auto nameEnd = line.find(':'); + if ((nameEnd == line.npos) || (line[nameEnd + 1] != ' ')) { + qCDebug(QGPGME_LOG) << "Unexpected line in AD_QUERY result:" << std::string{line}; + continue; + } + const std::string_view name = line.substr(0, nameEnd); + const std::string_view value = line.substr(nameEnd + 2); + result.push_back({_QStringFromStdStringView(name), _QStringFromStdStringView(value)}); + } + } + + return result; +} + +static QGpgMEADQueryJob::result_type run_ad_query(Context *ctx, const QString &filter, const QStringList &attributes, ADQueryOptions options) +{ + ADQueryResult result; + + Error err = setUpDirmngrAssuanConnection(ctx); + + if (!err) { + QStringList arguments; + if (options & ADQueryOption::RootDSE) { + arguments.push_back(u"--rootdse"_s); + } + if (options & ADQueryOption::SubstituteVariables) { + arguments.push_back(u"--subst"_s); + } + if (!attributes.empty()) { + arguments.push_back("--attr="_L1 + attributes.join(u',')); + } + arguments.push_back(u"--"_s); + arguments.push_back(filter); + const std::string cmd = std::string{"AD_QUERY "} += arguments.join(u' ').toStdString(); + err = ctx->assuanTransact(cmd.c_str()); + if (err) { + qCDebug(QGPGME_LOG) << "AD_QUERY failed with" << err; + } + } + + if (!err) { + const auto transaction = std::unique_ptr<DefaultAssuanTransaction>(dynamic_cast<DefaultAssuanTransaction*>(ctx->takeLastAssuanTransaction().release())); + const std::string source = transaction->firstStatusLine("SOURCE"); + const std::string rawData = transaction->data(); + if (rawData.empty()) { + qCDebug(QGPGME_LOG) << "No data returned for" << filter; + result = ADQueryResult{}; + } else { + qCDebug(QGPGME_LOG) << "Got a result for" << filter << "at" << source.c_str(); + result = ADQueryResult{parse_query_result(rawData), QString::fromStdString(source), {}}; + } + } + + return std::make_tuple(err ? ADQueryResult{err} : result, QString{}, Error{}); +} + +GpgME::Error QGpgMEADQueryJobPrivate::startIt() +{ + Q_Q(QGpgMEADQueryJob); + q->run([=](Context *ctx) { + return run_ad_query(ctx, m_filter, m_attributes, m_options); + }); + + return {}; +} + +ADQueryResult QGpgMEADQueryJobPrivate::execIt() +{ + Q_Q(QGpgMEADQueryJob); + const QGpgMEADQueryJob::result_type r = run_ad_query(q->context(), m_filter, m_attributes, m_options); + return std::get<0>(r); +} + +#include "moc_qgpgmeadqueryjob.cpp" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/qgpgmeadqueryjob.h new/qgpgme-2.2.0/src/qgpgmeadqueryjob.h --- old/qgpgme-2.1.0/src/qgpgmeadqueryjob.h 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/src/qgpgmeadqueryjob.h 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,69 @@ +/* + qgpgmeadqueryjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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_QGPGMEADQUERYJOB_H__ +#define __QGPGME_QGPGMEADQUERYJOB_H__ + +#include "adqueryjob.h" + +#include "adqueryresult.h" +#include "threadedjobmixin.h" + +namespace QGpgME +{ + +class QGpgMEADQueryJobPrivate; + +class QGpgMEADQueryJob +#ifdef Q_MOC_RUN + : public ADQueryJob +#else + : public _detail::ThreadedJobMixin<ADQueryJob, QGpgMEADQueryJobPrivate, std::tuple<ADQueryResult, QString, GpgME::Error> > +#endif +{ + Q_OBJECT +#ifdef Q_MOC_RUN +public Q_SLOTS: + void slotFinished(); +#endif +public: + explicit QGpgMEADQueryJob(GpgME::Context *context); + ~QGpgMEADQueryJob() override; + +private: + Q_DECLARE_PRIVATE(QGpgMEADQueryJob) +}; + +} + +#endif // __QGPGME_QGPGMEADQUERYJOB_H__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/qgpgmewkdlookupjob.cpp new/qgpgme-2.2.0/src/qgpgmewkdlookupjob.cpp --- old/qgpgme-2.1.0/src/qgpgmewkdlookupjob.cpp 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/qgpgmewkdlookupjob.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -37,7 +37,9 @@ #include "qgpgmewkdlookupjob.h" +#include "cryptoconfig.h" #include "debug.h" +#include "protocol.h" #include "qgpgme_debug.h" #include <gpgme++/context.h> @@ -59,8 +61,12 @@ static GpgME::Error startDirmngr(Context *assuanCtx) { - Error err; + // don't start dirmngr if it is disabled for gpg + if (QGpgME::cryptoConfig()->entry("gpg", "disable-dirmngr")->boolValue()) { + return Error::fromCode(GPG_ERR_NO_DIRMNGR); + } + Error err; auto spawnCtx = std::unique_ptr<Context>{Context::createForEngine(SpawnEngine, &err)}; if (err) { qCDebug(QGPGME_LOG) << "Error: Failed to get context for spawn engine (" << err << ")"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/qt6compat_p.h new/qgpgme-2.2.0/src/qt6compat_p.h --- old/qgpgme-2.1.0/src/qt6compat_p.h 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/qt6compat_p.h 2026-07-20 15:07:38.000000000 +0200 @@ -35,10 +35,11 @@ #include <QtGlobal> -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - +#include <QDebug> #include <QString> +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + namespace Qt { inline namespace Literals @@ -58,3 +59,10 @@ } // Qt #endif + +#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) +inline QDebug operator<<(QDebug s, const std::string &string) +{ + return s << QString::fromStdString(string); +} +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/src/util.h new/qgpgme-2.2.0/src/util.h --- old/qgpgme-2.1.0/src/util.h 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/src/util.h 2026-07-20 15:07:38.000000000 +0200 @@ -40,6 +40,7 @@ #include <gpgme.h> +#include <memory> #include <string> #include <vector> @@ -62,6 +63,27 @@ #endif } +namespace _qgpgme +{ + +static inline std::vector<std::string_view> split(const std::string_view s, char delimiter) +{ + std::vector<std::string_view> result; + std::string_view::size_type start = 0; + std::string_view::size_type end; + do { + end = s.find(delimiter, start); + if (end == s.npos) { + end = s.size(); + } + result.emplace_back(std::addressof(s[start]), end - start); + start = end + 1; + } while (end != s.size()); + return result; +} + +} + std::vector<std::string> toStrings(const QStringList &l); QStringList toFingerprints(const std::vector<GpgME::Key> &keys); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/tests/CMakeLists.txt new/qgpgme-2.2.0/tests/CMakeLists.txt --- old/qgpgme-2.1.0/tests/CMakeLists.txt 2026-05-18 14:24:04.000000000 +0200 +++ new/qgpgme-2.2.0/tests/CMakeLists.txt 2026-07-20 15:07:38.000000000 +0200 @@ -62,6 +62,7 @@ _g10_add_test(t-setprimaryuserid.cpp) _g10_add_test(t-tofuinfo.cpp) _g10_add_test(t-trustsignatures.cpp) +_g10_add_test(t-util.cpp) _g10_add_test(t-various.cpp) _g10_add_test(t-verify.cpp) _g10_add_test(t-wkdlookup.cpp) @@ -78,6 +79,7 @@ target_link_libraries(${_name} ${qgpgme_library} Gpgmepp) endmacro() +_g10_add_testprogram(run-adqueryjob.cpp) _g10_add_testprogram(run-decryptverifyarchivejob.cpp) _g10_add_testprogram(run-decryptverifyjob.cpp) _g10_add_testprogram(run-encryptarchivejob.cpp) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/tests/run-adqueryjob.cpp new/qgpgme-2.2.0/tests/run-adqueryjob.cpp --- old/qgpgme-2.1.0/tests/run-adqueryjob.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/tests/run-adqueryjob.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,132 @@ +/* + run-adqueryjob.cpp + + This file is part of QGpgME's test suite. + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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 <adqueryjob.h> +#include <adqueryresult.h> +#include <debug.h> +#include <protocol.h> + +#include <QCommandLineParser> +#include <QCoreApplication> + +#include <gpgme++/context.h> + +#include <iostream> + +using namespace GpgME; + +std::ostream &operator<<(std::ostream &os, const QString &s) +{ + return os << s.toLocal8Bit().constData(); +} + +struct CommandLineOptions { + bool asynchronous = false; + QString attributes; + QString email; +}; + +CommandLineOptions parseCommandLine(const QStringList &arguments) +{ + CommandLineOptions options; + + QCommandLineParser parser; + parser.setApplicationDescription("Test program for ADQueryJob"); + parser.addHelpOption(); + parser.addOptions({ + {"async", "Run the job asynchronously"}, + }); + parser.addPositionalArgument("attributes", "Comma separated list of attributes to ask for"); + parser.addPositionalArgument("email", "User to ask for"); + + parser.process(arguments); + + const auto args = parser.positionalArguments(); + if (args.size() != 2) { + parser.showHelp(1); + } + + options.asynchronous = parser.isSet("async"); + options.attributes = args[0]; + options.email = args[1]; + + return options; +} + +static void printResult(const QGpgME::ADQueryResult &result) +{ + if (result.error()) { + std::cout << "Error: " << result.error().asStdString() << std::endl; + } else { + std::cout << "Result: " << result << std::endl; + } +} + +int main(int argc, char **argv) +{ + GpgME::initializeLibrary(); + + QCoreApplication app{argc, argv}; + app.setApplicationName("run-adqueryjob"); + + const auto options = parseCommandLine(app.arguments()); + + Error err; + std::cout << "Querying AD for attributes " << options.attributes << " of user with email " << options.email << std::endl; + + auto job = std::unique_ptr<QGpgME::ADQueryJob>(QGpgME::openpgp()->adQueryJob()); + if (!job) { + std::cerr << "Error: Could not create job to query AD" << std::endl; + return 1; + } + const QString filter = QStringLiteral("(&(objectcategory=person)(objectclass=user) (|(userPrincipalName=%1) (mail=%1)))").arg(options.email); + if (options.asynchronous) { + QObject::connect(job.get(), &QGpgME::ADQueryJob::result, &app, [](const QGpgME::ADQueryResult &result, const QString &, const GpgME::Error &) { + printResult(result); + qApp->quit(); + }); + err = job->start(filter, options.attributes.split(u','), QGpgME::ADQueryOption::SubstituteVariables); + if (err) { + std::cerr << "Error: " << err << std::endl; + return 1; + } + job.release(); // NOLINT(bugprone-unused-return-value); job will delete itself when it's done + return app.exec(); + } else { + printResult(job->exec(filter, options.attributes.split(u','), QGpgME::ADQueryOption::SubstituteVariables)); + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/qgpgme-2.1.0/tests/t-util.cpp new/qgpgme-2.2.0/tests/t-util.cpp --- old/qgpgme-2.1.0/tests/t-util.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/qgpgme-2.2.0/tests/t-util.cpp 2026-07-20 15:07:38.000000000 +0200 @@ -0,0 +1,91 @@ +/* + t-util.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2026 g10 Code GmbH + Software engineering by Ingo Klöcker <[email protected]> + + 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. +*/ + +#include "util.h" + +#include <qt6compat_p.h> + +#include <QString> +#include <QTest> + +using namespace std::literals; + +class TestUtil : public QObject +{ + Q_OBJECT +public: + using QObject::QObject; + +private Q_SLOTS: + void test_split() + { + using VecSV = std::vector<std::string_view>; + { + const auto result = _qgpgme::split(""sv, ','); + QCOMPARE(result, VecSV{""sv}); + } + { + const auto result = _qgpgme::split("abc"sv, ','); + QCOMPARE(result, VecSV{"abc"sv}); + } + { + const auto result = _qgpgme::split("abc,def"sv, ','); + const auto expected = VecSV{"abc"sv, "def"sv}; + QCOMPARE(result, expected); + } + { + const auto result = _qgpgme::split(",abc"sv, ','); + const auto expected = VecSV{""sv, "abc"sv}; + QCOMPARE(result, expected); + } + { + const auto result = _qgpgme::split("abc,"sv, ','); + const auto expected = VecSV{"abc"sv, ""sv}; + QCOMPARE(result, expected); + } + { + const auto result = _qgpgme::split("abc,,def"sv, ','); + const auto expected = VecSV{"abc"sv, ""sv, "def"sv}; + QCOMPARE(result, expected); + } + { + const auto result = _qgpgme::split(","sv, ','); + const auto expected = VecSV{""sv, ""sv}; + QCOMPARE(result, expected); + } + } +}; + +QTEST_GUILESS_MAIN(TestUtil) + +#include "t-util.moc" ++++++ qgpgme.keyring ++++++ --- /var/tmp/diff_new_pack.LdYxrE/_old 2026-08-02 23:14:25.804286742 +0200 +++ /var/tmp/diff_new_pack.LdYxrE/_new 2026-08-02 23:14:25.808286880 +0200 @@ -66,30 +66,39 @@ KdYretbGQwo+vXLXfWk9QKHXwF2IdkUSnL/IyFje/thujBW2UJZMTO3vD830px2G k4h1BBATCAAdFiEEAvON/3Mf+XywOaHaVJ5pXpBboggFAmgeDcYACgkQVJ5pXpBb ogis0wD9H38UP4TH3Y19d7mnkSifeHkldKc4iUP/Ok3w/+Di5qkA/iA7xLTtiuhW -jhnuwb68kTxh8Beg023EiqsJb9qWnY8umFMEYWlKoxMJKyQDAwIIAQEHAgMEXpcP -02ZRAOCLJg1uGzUMwnXiYjDzXbBjUdXH/hBZhaIG6eGu9IXFVvOyMPv9a/6/duYw -+sv4zYMvIWJJ7A2ZxLQkR251UEcuY29tIChSZWxlYXNlIFNpZ25pbmcgS2V5IDIw -MjEpiJoEExMIAEIWIQQC843/cx/5fLA5odpUnmlekFuiCAUCYWlKowIbAwUJD3HX -igULCQgHAgMiAgEGFQoJCAsCBBYCAwECHgcCF4AACgkQVJ5pXpBboghOSgD9FhqN -pOXV4QFT8Z2bXajeOsjnk3nFkrZdOpLHblyVXKMA/RfAxb86Dn40PWuLdsCoANVa -UENSzDPzBjGxvQLiRgGSiHUEEBYKAB0WIQRtqm5kp20oQFcbSQJSiJe4JkA62gUC -YWlO8QAKCRBSiJe4JkA62slAAQCHtjLKSMDL9CzXILeOLyIF8hWc9e9uWsjHdJFH -IPBELwEAq1lsS4pO0+WCQtSAyV5Nxkn+8SEkT4a99D2jmBYKoQWIdQQQFgoAHRYh -BMHTS2khnkruwLocIeP9/yGORbcrBQJhaU9aAAoJEOP9/yGORbcrHh4BAOnpoZI3 -99TjEuXxFK9BRWNUD5oJOsxBHeFHCrDyWIXbAQDc7cQLHPp7X4Ogi1igkEEsovB6 -IiewZn/6HldiuldOAJhzBGmcEd0TCSskAwMCCAEBCwMDBFT19o0ILvhUHY7++XKs -7VXucAoXgkq5WEvqBsIzGGSrWlC6fc+L6bDS6YSSw2yRMWmeY7fukPLaDY/BtAFe -6LYHos4tyUkjHcUliMyEPvnIUapDL+ZS8I+ihkt4wlfWPrQkR251UEcuY29tIChS -ZWxlYXNlIFNpZ25pbmcgS2V5IDIwMjYpiNUEExMJAF0WIQQUkyad5h8SSqaaMW46 -3zTr27IApAUCaZwU6xsUgAAAAAAEAA5tYW51MiwyLjUrMS4xMSwyLDICGwMFCQ8M -a4AFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQOt8069uyAKS3FAF/d81D -kMhp98EHpDa/ZLbvIZuTDvz/wngLOzHvMLy+zAm1UQKU4nRT9YCjiz7/hS55AX4w -h36hfXlNvTpP8tXjY+MNo7oMuHx+a23KgB77KTxKCMoF/ZAetYFhVwcubFRk5KOI -dQQQEwgAHRYhBALzjf9zH/l8sDmh2lSeaV6QW6IIBQJpnBZZAAoJEFSeaV6QW6II -+a4BAJsGiYwA0Vwt0p2pxeSh/IGJTSHfFWYkEMf3pt5HGBGBAP9Hxc04lXgkr5yS -AMOkqdhB2Y/VsrU5IltHfPNRWrBUsYh1BBAWCgAdFiEEbapuZKdtKEBXG0kCUoiX -uCZAOtoFAmmcFpkACgkQUoiXuCZAOtq2fQEA4HuVHLXfTB9WNLA07Tuc8jziaGjG -d3g9PrWIQiUMfsEA/2MPh5wwTaX+8YsBc+DwBGtNshzReN+OBDpnyk/ILEoM -=rCfC +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 +jgQ6Z8pPyCxKDA== +=/vKN -----END PGP PUBLIC KEY BLOCK-----
