Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package gpgmepp for openSUSE:Factory checked 
in at 2026-06-01 17:58:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/gpgmepp (Old)
 and      /work/SRC/openSUSE:Factory/.gpgmepp.new.1937 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "gpgmepp"

Mon Jun  1 17:58:44 2026 rev:2 rq:1356111 version:2.1.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/gpgmepp/gpgmepp.changes  2025-07-21 
19:58:36.290878672 +0200
+++ /work/SRC/openSUSE:Factory/.gpgmepp.new.1937/gpgmepp.changes        
2026-06-01 17:58:45.965284382 +0200
@@ -1,0 +2,10 @@
+Sun May 31 06:51:22 UTC 2026 - Andreas Stieger <[email protected]>
+
+- Update to 2.1.0:
+  * New methods to query the compliance of encryption results
+  * New function Subkey::keyGrips to get the list of keygrips for
+    a subkey using combined algorithms
+  * New function Context::generateRandomZBase32String to get a
+    cryptographically strong string of z-base-32 characters
+
+-------------------------------------------------------------------

Old:
----
  gpgmepp-2.0.0.tar.xz
  gpgmepp-2.0.0.tar.xz.sig

New:
----
  gpgmepp-2.1.0.tar.xz
  gpgmepp-2.1.0.tar.xz.sig

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ gpgmepp.spec ++++++
--- /var/tmp/diff_new_pack.gp8Szq/_old  2026-06-01 17:58:48.945407975 +0200
+++ /var/tmp/diff_new_pack.gp8Szq/_new  2026-06-01 17:58:48.965408805 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package gpgmepp
 #
-# Copyright (c) 2025 Andreas Stieger <[email protected]>
+# Copyright (c) 2026 Andreas Stieger <[email protected]>
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %define sover 7
 Name:           gpgmepp
-Version:        2.0.0
+Version:        2.1.0
 Release:        0
 Summary:        C++ bindings/wrapper for GPGME
 License:        LGPL-2.0-or-later AND LGPL-2.1-or-later

++++++ gpgmepp-2.0.0.tar.xz -> gpgmepp-2.1.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/CMakeLists.txt 
new/gpgmepp-2.1.0/CMakeLists.txt
--- old/gpgmepp-2.0.0/CMakeLists.txt    2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/CMakeLists.txt    2026-05-18 12:04:51.000000000 +0200
@@ -21,7 +21,7 @@
 
 cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
 
-set(FULL_VERSION "2.0.0")
+set(FULL_VERSION "2.1.0")
 
 string(REGEX MATCH "^[0-9]+.[0-9]+.[0-9]+" cmake_compat_version 
${FULL_VERSION})
 project(gpgmepp VERSION ${cmake_compat_version})
@@ -35,8 +35,8 @@
 #   (Interfaces added/removed/changed: CURRENT++, REVISION=0)
 #   (Interfaces added:                 AGE++)
 #   (Interfaces removed:               AGE=0)
-set(LIBGPGMEPP_LT_CURRENT "7")
-set(LIBGPGMEPP_LT_AGE "0")
+set(LIBGPGMEPP_LT_CURRENT "8")
+set(LIBGPGMEPP_LT_AGE "1")
 set(LIBGPGMEPP_LT_REVISION "0")
 math(EXPR LIBGPGMEPP_SOVERSION "${LIBGPGMEPP_LT_CURRENT} - 
${LIBGPGMEPP_LT_AGE}")
 
@@ -48,6 +48,7 @@
 # The following option is used in gpg4win to distinguish the 32-bit build from
 # the 64-bit build
 option(PKGCONFIG_HOST "The host value to write in the pkgconfig file" "")
+option(CONFIGURE_FOR_DISTRIBUTION "Configure only for `make dist`, etc., 
ignoring required dependencies" OFF)
 
 set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules 
${CMAKE_MODULE_PATH})
 
@@ -63,9 +64,13 @@
 include(GNUInstallDirs)
 
 find_package(LibGpgError ${GPG_ERROR_REQUIRED_VERSION})
-set_package_properties(LibGpgError PROPERTIES TYPE REQUIRED)
 find_package(Gpgme ${GPGME_REQUIRED_VERSION})
-set_package_properties(Gpgme PROPERTIES TYPE REQUIRED)
+if (CONFIGURE_FOR_DISTRIBUTION)
+    message(WARNING "Configuring only for running `make dist`, etc., ignoring 
required dependencies")
+else()
+    set_package_properties(LibGpgError PROPERTIES TYPE REQUIRED)
+    set_package_properties(Gpgme PROPERTIES TYPE REQUIRED)
+endif()
 
 g10_get_full_version()
 
@@ -113,10 +118,12 @@
 include(G10GitHooks)
 g10_configure_git_hooks()
 
-add_subdirectory(src)
+if (LibGpgError_FOUND AND Gpgme_FOUND)
+    add_subdirectory(src)
 
-if(BUILD_TESTING AND ENABLE_SHARED)
-    add_subdirectory(tests)
+    if(BUILD_TESTING AND ENABLE_SHARED)
+        add_subdirectory(tests)
+    endif()
 endif()
 
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/ChangeLog new/gpgmepp-2.1.0/ChangeLog
--- old/gpgmepp-2.0.0/ChangeLog 2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/ChangeLog 2026-05-18 12:04:51.000000000 +0200
@@ -1,3 +1,109 @@
+2026-05-18  Werner Koch  <[email protected]>
+
+       Release 2.1.0.
+       + commit 6a99d7eef09aedd768356792f38aca2cc03659da
+
+
+2026-04-21  Ingo Klöcker  <[email protected]>
+
+       Add support for new flags of encryption results.
+       + commit f12b36209758e82a53a8bfcc4ac0889bc9ecc0ed
+       * src/encryptionresult.h, src/encryptionresult.cpp (class
+       EncryptionResult): New methods isDeVs and isBetaCompliance.
+       * src/encryptionresult.cpp (EncryptionResult::Private): New
+       field res.
+       (EncryptionResult::Private::Private): Change type of argument r from
+       pointer to const-reference. Copy-construct res from r. Clear
+       invalid_recipients field of res after copying invalid recipients.
+       (EncryptionResult::init): Adapt call of Private c'tor to changed
+       argument type.
+       (operator<<): Add new flags.
+
+2026-02-18  Ingo Klöcker  <[email protected]>
+
+       Improve API to generate random bytes and z-base-32 characters.
+       + commit fea0862b4f7857f780d417e5e178fb2753f2e901
+       * src/context.h (enum class RandomMode): Deprecate.
+       (generateRandomBytes): Deprecate overload taking RandomMode parameter.
+       * src/context.h, src/context.cpp (generateRandomBytes): New overload
+       taking only size_t parameter.
+       (generateRandomZBase32String): New.
+       * src/randomresults.h (RandomZBase32StringResult): New.
+
+       * tests/run-genrandom.cpp (main): Use generateRandomZBase32String
+       instead of deprecated generateRandomBytes.
+
+       Avoid copy of generated random bytes.
+       + commit 7025cb4b211bcda5e07620f12eb806c14ca95e0d
+       * src/randomresults.h (class RandomBytesResult): Add constructor for
+       moving value into result.
+       * src/context.cpp (Context::generateRandomBytes): Use new constructor.
+
+2026-02-17  Ingo Klöcker  <[email protected]>
+
+       tests: Fix conversion of random zbase32 data to string.
+       + commit fade4bbe630b7e597d1cd3308819110490cae598
+       * tests/run-genrandom.cpp (main): Pass data to std::string constructor
+       instead of copying it byte by byte.
+
+2025-12-10  Ingo Klöcker  <[email protected]>
+
+       Use DeletionFlags in key deletion API.
+       + commit 527df234fb2fea51dfc6e9f84f3c98914b38b88e
+       * src/context.h, src/context.cpp (Context::startKeyDeletion): Add
+       overload taking DeletionFlags.
+       * src/context.cpp (Context::startKeyDeletion): Make overload taking a
+       bool use new overload.
+       * src/context.h (Context::deleteKey, Context::startKeyDeletion): Mark
+       overloads taking a bool as deprecated.
+
+       Use new Flags template for new Deletion flags.
+       + commit d8098f30da95621dff88d815ab29534fec5014e4
+       * src/global.h (DeletionFlags): Rename to...
+       (DeletionFlag): ...this. Change underlying type to unsigned int. Remove
+       UseDefaults enum value.
+       (DeletionFlags): New type for combinations of DeletionFlag. Define enum
+       flag operators for this type.
+       (operator|): Remove overload for DeletionFlags.
+       * src/context.cpp (Context::deleteKey): Adapt to above changes.
+
+       Add template class for type-safe enum-based flags.
+       + commit bb44fc70e48e8be61f5ab6352796f5c0610dd848
+       * src/CMakeLists.txt (Gpgmepp_HEADERS): Add new file.
+       * src/flags.h: New.
+       * tests/CMakeLists.txt: Add new test.
+       * tests/t-flags.cpp: New.
+
+2025-11-19  Tobias Fella  <[email protected]>
+
+       Allow passing flags to Context::deleteKey.
+       + commit 550a0666b25a84534c83237b211053c875fe4795
+       GnuPG-Bug-ID: 7538
+
+2025-10-29  Ingo Klöcker  <[email protected]>
+
+       Add function to get keygrips of subkey using combined algorithms.
+       + commit 71b7d24a2782d56be9560d2c6a44211aff07e0f1
+       * src/key.cpp, src/key.h (Subkey::keyGrips): New.
+
+       Add internal utility function for splitting a string into string views.
+       + commit fa1e892b1414da07aa467bda295f8981b191374d
+       * src/util.cpp, src/util.h (split_into_string_views): New.
+
+       * tests/CMakeLists.txt: Add macro _g10_add_test. Add new test.
+       * tests/t-utils.cpp: New.
+
+2025-10-24  Ingo Klöcker  <[email protected]>
+
+       Use gpgme_ssize_t everywhere.
+       + commit 268f2feea0b0c7025016170a4a2e3dee2c3aa0fd
+       * src/editinteractor.cpp (edit_interactor_callback_impl): Replace
+       ssize_t with gpgme_ssize_t.
+
+       build: Fix install with MSVC.
+       + commit e0b20e967654446dbe06b09e8d73cc97e02aac2b
+       * CMakeLists.txt: Add missing DESTINATION keyword to install arguments.
+
 2025-06-03  Werner Koch  <[email protected]>
 
        Release 2.0.0.
@@ -6,6 +112,13 @@
 
 2025-06-03  Ingo Klöcker  <[email protected]>
 
+       build: Add option CONFIGURE_FOR_DISTRIBUTION.
+       + commit 592efbfcfb61be34ede8ebe66ee8bc3952c131c6
+       * CMakeLists.txt: Add option CONFIGURE_FOR_DISTRIBUTION. Set
+       LibGpgError and Gpgme as required if option CONFIGURE_FOR_DISTRIBUTION
+       is not set. Add src (and tests) only if required dependencies were
+       found.
+
        build: Fix logic for appending "-unknown" to version number.
        + commit 1e948b3f3ee10806eaee282e489609fa370277d8
        * cmake/modules/G10GetFullVersion.cmake (G10_GET_FULL_VERSION): Use
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/NEWS new/gpgmepp-2.1.0/NEWS
--- old/gpgmepp-2.0.0/NEWS      2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/NEWS      2026-05-18 12:04:51.000000000 +0200
@@ -1,3 +1,27 @@
+Noteworthy changes in version 2.1.0 (2026-05-18)  [C8/A1/R0]
+------------------------------------------------
+
+ * New methods to query the compliance of encryption results.   [T6702]
+
+ * New function Subkey::keyGrips to get the list of keygrips for
+   a subkey using combined algorithms.
+
+ * New function Context::generateRandomZBase32String to get a
+   cryptographically strong string of z-base-32 characters.  [T8108]
+
+ * Interface changes relative to the 2.0.0 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ DeletionFlag                                NEW.
+ DeletionFlags                               NEW.
+ Context::deleteKey                     CHANGED: New overload; deprecated old.
+ Context::startKeyDeletion              CHANGED: New overload; deprecated old.
+ Context::RandomMode                         DEPRECATED.
+ Context::generateRandomBytes           CHANGED: New overload; deprecated old.
+ Context::generateRandomZBase32String        NEW.
+ Subkey::keyGrips                            NEW.
+ EncryptionResult::isDeVs                    NEW.
+ EncryptionResult::isBetaCompliance          NEW.
+
 Noteworthy changes in version 2.0.0 (2025-06-03)  [C7/A0/R0]
 ------------------------------------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/VERSION new/gpgmepp-2.1.0/VERSION
--- old/gpgmepp-2.0.0/VERSION   2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/VERSION   2026-05-18 12:04:51.000000000 +0200
@@ -1,2 +1,2 @@
-2.0.0
-301d39f8b97a79369292280e201e45f472d71e91
+2.1.0
+6a99d7eef09aedd768356792f38aca2cc03659da
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/cmake/modules/g10_sign-release.sh.in 
new/gpgmepp-2.1.0/cmake/modules/g10_sign-release.sh.in
--- old/gpgmepp-2.0.0/cmake/modules/g10_sign-release.sh.in      2025-06-03 
15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/cmake/modules/g10_sign-release.sh.in      2026-05-18 
12:04:51.000000000 +0200
@@ -33,12 +33,21 @@
     exit 2
 fi
 mysignkey="$x"
-files1="@[email protected]"
-files2="@[email protected]
-       @[email protected]
+files1=
+suffix=
+for suf in xz bz2 gz; do
+    if [ -f "@[email protected].$suf" ]; then
+       files1="@[email protected].$suf"
+       files2="@[email protected].$suf.sig"
+       suffix=$suf
+       break
+    fi
+done
+files2="$files2
+        @[email protected]
        @[email protected]"
 echo "/* Signing the source tarball ..."
-gpg -sbu $mysignkey @[email protected]
+gpg -sbu $mysignkey @[email protected].$suffix
 cat @[email protected] >swdb.snippet
 echo >>swdb.snippet
 sha1sum ${files1} >>swdb.snippet
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/CMakeLists.txt 
new/gpgmepp-2.1.0/src/CMakeLists.txt
--- old/gpgmepp-2.0.0/src/CMakeLists.txt        2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/src/CMakeLists.txt        2026-05-18 12:04:51.000000000 
+0200
@@ -80,6 +80,7 @@
     error.h
     eventloopinteractor.h
     exception.h
+    flags.h
     global.h
     gpgaddexistingsubkeyeditinteractor.h
     gpgadduserideditinteractor.h
@@ -195,7 +196,7 @@
 
 if(ENABLE_SHARED)
     if (MSVC)
-        install(TARGETS Gpgmepp EXPORT GpgmeppTargets 
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+        install(TARGETS Gpgmepp EXPORT GpgmeppTargets DESTINATION 
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
     else()
         install(TARGETS Gpgmepp EXPORT GpgmeppTargets)
     endif()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/context.cpp 
new/gpgmepp-2.1.0/src/context.cpp
--- old/gpgmepp-2.0.0/src/context.cpp   2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/context.cpp   2026-05-18 12:04:51.000000000 +0200
@@ -760,14 +760,24 @@
 
 Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
 {
+    return deleteKey(key, allowSecretKeyDeletion ? 
DeletionFlags{DeletionFlag::AllowSecret} : DeletionFlags{});
+}
+
+Error Context::deleteKey(const Key &key, DeletionFlags flags)
+{
     d->lastop = Private::Delete;
-    return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), 
int(allowSecretKeyDeletion)));
+    return Error(d->lasterr = gpgme_op_delete_ext(d->ctx, key.impl(), 
flags.toUnderlyingType()));
 }
 
 Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
 {
+    return startKeyDeletion(key, allowSecretKeyDeletion ? 
DeletionFlags{DeletionFlag::AllowSecret} : DeletionFlags{});
+}
+
+Error Context::startKeyDeletion(const Key &key, DeletionFlags flags)
+{
     d->lastop = Private::Delete;
-    return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), 
int(allowSecretKeyDeletion)));
+    return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), 
flags.toUnderlyingType()));
 }
 
 Error Context::passwd(const Key &key)
@@ -1829,6 +1839,8 @@
   return gpgme_get_ctx_flag(d->ctx, name);
 }
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 RandomBytesResult Context::generateRandomBytes(size_t count, RandomMode mode)
 {
     RandomBytesResult::value_type randomBytes(count);
@@ -1837,7 +1849,19 @@
     if (d->lasterr) {
         return RandomBytesResult{Error{d->lasterr}};
     }
-    return RandomBytesResult{randomBytes};
+    return RandomBytesResult{std::move(randomBytes)};
+}
+#pragma GCC diagnostic pop
+
+RandomBytesResult Context::generateRandomBytes(size_t count)
+{
+    RandomBytesResult::value_type randomBytes(count);
+    d->lasterr = gpgme_op_random_bytes(d->ctx, GPGME_RANDOM_MODE_NORMAL,
+                                       reinterpret_cast<char 
*>(randomBytes.data()), count);
+    if (d->lasterr) {
+        return RandomBytesResult{Error{d->lasterr}};
+    }
+    return RandomBytesResult{std::move(randomBytes)};
 }
 
 RandomValueResult Context::generateRandomValue(unsigned int limit)
@@ -1850,6 +1874,17 @@
     return RandomValueResult{static_cast<unsigned int>(randomValue)};
 }
 
+RandomZBase32StringResult Context::generateRandomZBase32String()
+{
+    std::string randomString(30, '\0');
+    d->lasterr = gpgme_op_random_bytes(d->ctx, GPGME_RANDOM_MODE_ZBASE32,
+                                       randomString.data(), 31);
+    if (d->lasterr) {
+        return RandomZBase32StringResult{Error{d->lasterr}};
+    }
+    return RandomZBase32StringResult{std::move(randomString)};
+}
+
 // Engine Spawn stuff
 Error Context::spawn(const char *file, const char *argv[],
                      Data &input, Data &output, Data &err,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/context.h 
new/gpgmepp-2.1.0/src/context.h
--- old/gpgmepp-2.0.0/src/context.h     2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/context.h     2026-05-18 12:04:51.000000000 +0200
@@ -57,6 +57,7 @@
 class VfsMountResult;
 class RandomBytesResult;
 class RandomValueResult;
+class RandomZBase32StringResult;
 
 class EngineInfo;
 
@@ -249,8 +250,8 @@
     // Key Deletion
     //
 
-    GpgME::Error deleteKey(const Key &key, bool allowSecretKeyDeletion = 
false);
-    GpgME::Error startKeyDeletion(const Key &key, bool allowSecretKeyDeletion 
= false);
+    GpgME::Error deleteKey(const Key &key, DeletionFlags flags);
+    GpgME::Error startKeyDeletion(const Key &key, DeletionFlags flags);
 
     //
     // Passphrase changing
@@ -537,14 +538,41 @@
     // Random values
     //
     //
-    enum class RandomMode {
+    enum class GPGMEPP_DEPRECATED RandomMode {
         Normal = 0,
         ZBase32 = 1
     };
-    RandomBytesResult generateRandomBytes(size_t count, RandomMode mode = 
RandomMode::Normal);
+    /*!
+     * Generate random bytes.
+     *
+     * This function creates a buffer of \a count bytes and fills this buffer 
by calling
+     * gpgme_op_random_bytes. \a count must be at most \c 1024. If \a mode is 
\c ZBase32
+     * then \a count must be at least \c 31. In this case the buffer is filled 
with 30
+     * ASCII characters followed by a null byte; the remainder of the buffer 
is uninitialized.
+     *
+     * This function is deprecated. For \c Normal mode use the other overload 
of
+     * generateRandomBytes. For \c ZBase32 mode use 
generateRandomZBase32String.
+     */
+    GPGMEPP_DEPRECATED RandomBytesResult generateRandomBytes(size_t count, 
RandomMode mode);
 
+    /*!
+     * Generate random bytes.
+     *
+     * This function creates a buffer of \a count bytes and fills this buffer 
with random
+     * bytes retrieved from gpg. \a count must be at most \c 1024.
+     */
+    RandomBytesResult generateRandomBytes(size_t count);
+
+    /*!
+     * Generate an unbiased random value in the range [0, \a limit).
+     */
     RandomValueResult generateRandomValue(unsigned int limit);
 
+    /*!
+     * Generate a string with 30 random z-base-32 characters.
+     */
+    RandomZBase32StringResult generateRandomZBase32String();
+
     //
     //
     // G13 crypto container operations
@@ -632,6 +660,8 @@
                                                unsigned long reserved,
                                                unsigned long expires,
                                                unsigned int flags);
+    GPGMEPP_DEPRECATED GpgME::Error deleteKey(const Key &key, bool 
allowSecretKeyDeletion = false);
+    GPGMEPP_DEPRECATED GpgME::Error startKeyDeletion(const Key &key, bool 
allowSecretKeyDeletion = false);
 
 private:
     // Helper functions that need to be context because they rely
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/editinteractor.cpp 
new/gpgmepp-2.1.0/src/editinteractor.cpp
--- old/gpgmepp-2.0.0/src/editinteractor.cpp    2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/src/editinteractor.cpp    2026-05-18 12:04:51.000000000 
+0200
@@ -134,7 +134,7 @@
                     // if there's a result, write it:
                     if (*result) {
                         gpgme_err_set_errno(0);
-                        const ssize_t len = std::strlen(result);
+                        const gpgme_ssize_t len = std::strlen(result);
                         if (writeAll(fd, result, len) != len) {
                             err = Error::fromSystemError();
                             if (ei->debug) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/encryptionresult.cpp 
new/gpgmepp-2.1.0/src/encryptionresult.cpp
--- old/gpgmepp-2.0.0/src/encryptionresult.cpp  2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/src/encryptionresult.cpp  2026-05-18 12:04:51.000000000 
+0200
@@ -43,12 +43,9 @@
 class GpgME::EncryptionResult::Private
 {
 public:
-    explicit Private(const gpgme_encrypt_result_t r)
+    explicit Private(const _gpgme_op_encrypt_result &r) : res(r)
     {
-        if (!r) {
-            return;
-        }
-        for (gpgme_invalid_key_t ik = r->invalid_recipients ; ik ; ik = 
ik->next) {
+        for (gpgme_invalid_key_t ik = res.invalid_recipients ; ik ; ik = 
ik->next) {
             gpgme_invalid_key_t copy = new _gpgme_invalid_key(*ik);
             if (ik->fpr) {
                 copy->fpr = strdup(ik->fpr);
@@ -56,6 +53,7 @@
             copy->next = nullptr;
             invalid.push_back(copy);
         }
+        res.invalid_recipients = nullptr;
     }
     ~Private()
     {
@@ -65,6 +63,7 @@
         }
     }
 
+    _gpgme_op_encrypt_result res;
     std::vector<gpgme_invalid_key_t> invalid;
 };
 
@@ -89,11 +88,21 @@
     if (!res) {
         return;
     }
-    d.reset(new Private(res));
+    d.reset(new Private(*res));
 }
 
 make_standard_stuff(EncryptionResult)
 
+bool GpgME::EncryptionResult::isDeVs() const
+{
+    return d && d->res.is_de_vs;
+}
+
+bool GpgME::EncryptionResult::isBetaCompliance() const
+{
+    return d && d->res.beta_compliance;
+}
+
 unsigned int GpgME::EncryptionResult::numInvalidRecipients() const
 {
     return d ? d->invalid.size() : 0 ;
@@ -144,7 +153,9 @@
 {
     os << "GpgME::EncryptionResult(";
     if (!result.isNull()) {
-        os << "\n error:        " << result.error()
+        os << "\n error:            " << result.error()
+           << "\n isDeVs:           " << result.isDeVs()
+           << "\n isBetaCompliance: " << result.isBetaCompliance()
            << "\n invalid recipients:\n";
         const std::vector<InvalidRecipient> ir = 
result.invalidEncryptionKeys();
         std::copy(ir.begin(), ir.end(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/encryptionresult.h 
new/gpgmepp-2.1.0/src/encryptionresult.h
--- old/gpgmepp-2.0.0/src/encryptionresult.h    2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/src/encryptionresult.h    2026-05-18 12:04:51.000000000 
+0200
@@ -64,6 +64,9 @@
 
     bool isNull() const;
 
+    bool isDeVs() const;
+    bool isBetaCompliance() const;
+
     unsigned int numInvalidRecipients() const;
 
     InvalidRecipient invalidEncryptionKey(unsigned int index) const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/flags.h 
new/gpgmepp-2.1.0/src/flags.h
--- old/gpgmepp-2.0.0/src/flags.h       1970-01-01 01:00:00.000000000 +0100
+++ new/gpgmepp-2.1.0/src/flags.h       2026-05-18 12:04:51.000000000 +0200
@@ -0,0 +1,235 @@
+/*
+    flags.h - helper for bitwise flag-like operations on scoped enums
+
+    Copyright (c) 2024 Zaven Maradyan <[email protected]>
+    Copyright (c) 2025 g10 Code GmbH
+    Software engineering by Ingo Klöcker <[email protected]>
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this source file (the "Materials"), to deal in the Materials
+    without restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies of the
+    Materials, and to permit persons to whom the Materials is furnished to do
+    so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Materials.
+
+    THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER
+    DEALINGS IN THE MATERIALS.
+
+    SPDX-License-Identifier: MIT
+*/
+
+#ifndef __GPGMEPP_FLAGS_H__
+#define __GPGMEPP_FLAGS_H__
+
+// Based on the BitFlags class template published at
+// https://voithos.io/articles/type-safe-enum-class-bit-flags/
+// under the MIT license.
+// The names of the member functions were changed to match the API of 
std::bitset.
+
+#include <bitset>
+#include <initializer_list>
+#include <iosfwd>
+#include <type_traits>
+
+namespace GpgME
+{
+
+// Helper class for bitwise flag-like operations on scoped enums.
+//
+// This class provides a way to represent combinations of enum values without
+// directly overloading operators on the enum type itself. This approach
+// avoids ambiguity in the type system and allows the enum type to continue
+// representing a single value, while the Flags can hold a combination
+// of enum values.
+//
+// Example usage:
+//
+// enum class DeletionFlag : unsigned int {
+//     AllowSecret = (1 << 0),
+//     Force = (1 << 1),
+// };
+// using DeletionFlags = Flags<DeletionFlag>;
+//
+// DeletionFlags flags = { DeletionFlag::AllowSecret, DeletionFlag::Force };
+// flags.reset(DeletionFlag::Force);
+// if (flags.test(DeletionFlag::AllowSecret)) {
+//     // ...
+// }
+// flags |= DeletionFlag::Force;
+//
+// Optionally, you can define binary operators for two flags for more
+// convenient combination of multiple flags:
+//
+// GPGMEPP_DEFINE_ENUM_FLAG_OPERATORS(DeletionFlags)
+//
+// DeletionFlags forceDeleteOfSecret = DeletionFlag::AllowSecret | 
DeletionFlag::Force;
+template <typename Enum, std::size_t _Nb = sizeof(Enum) * 8>
+class Flags {
+    using UnderlyingT = std::underlying_type_t<Enum>;
+
+public:
+    using enum_type = Enum;
+
+    static const std::size_t number_of_bits = _Nb;
+
+    // Rule of zero: default copy/move constructor/assignment operators are 
fine
+    constexpr inline Flags() = default;
+    constexpr inline explicit Flags(Enum flag)
+        : mFlags(toUnderlying(flag))
+    {
+    }
+    constexpr inline Flags(std::initializer_list<Enum> flags)
+    {
+        for (Enum flag : flags) {
+            mFlags |= toUnderlying(flag);
+        }
+    }
+
+    static constexpr inline Flags fromUnderlyingType(UnderlyingT flags)
+    {
+        return Flags{flags};
+    }
+    constexpr inline UnderlyingT toUnderlyingType() const
+    {
+        return mFlags;
+    }
+
+    //! Tests if flag \a flag is set.
+    constexpr inline bool test(Enum flag) const
+    {
+        return (mFlags & toUnderlying(flag)) == toUnderlying(flag);
+    }
+    //! Sets the flag \a flag if \a value is \c true. Otherwise, the flag is 
reset.
+    constexpr inline Flags &set(Enum flag, bool value = true)
+    {
+        return value ? (*this |= flag) : (*this &= ~Flags(flag));
+    }
+    //! Sets the flag \a flag to \c false.
+    constexpr inline Flags &reset(Enum flag)
+    {
+        return (*this &= ~Flags(flag));
+    }
+    //! Sets all flags to false.
+    constexpr inline Flags &reset()
+    {
+        mFlags = static_cast<UnderlyingT>(0);
+        return *this;
+    }
+
+    constexpr inline explicit operator bool() const {
+        return mFlags != static_cast<UnderlyingT>(0);
+    }
+
+    friend constexpr inline Flags operator|(Flags lhs, Flags rhs) {
+        return Flags(lhs.mFlags | rhs.mFlags);
+    }
+    friend constexpr inline Flags operator|(Flags lhs, Enum rhs) {
+        return Flags(lhs.mFlags | toUnderlying(rhs));
+    }
+    friend constexpr inline Flags operator|(Enum lhs, Flags rhs) {
+        return Flags(toUnderlying(lhs) | rhs.mFlags);
+    }
+
+    friend constexpr inline Flags operator&(Flags lhs, Flags rhs) {
+        return Flags(lhs.mFlags & rhs.mFlags);
+    }
+    friend constexpr inline Flags operator&(Flags lhs, Enum rhs) {
+        return Flags(lhs.mFlags & toUnderlying(rhs));
+    }
+    friend constexpr inline Flags operator&(Enum lhs, Flags rhs) {
+        return Flags(toUnderlying(lhs) & rhs.mFlags);
+    }
+
+    friend constexpr inline Flags operator^(Flags lhs, Flags rhs) {
+        return Flags(lhs.mFlags ^ rhs.mFlags);
+    }
+    friend constexpr inline Flags operator^(Flags lhs, Enum rhs) {
+        return Flags(lhs.mFlags ^ toUnderlying(rhs));
+    }
+    friend constexpr inline Flags operator^(Enum lhs, Flags rhs) {
+        return Flags(toUnderlying(lhs) ^ rhs.mFlags);
+    }
+
+    constexpr inline Flags &operator|=(Flags other) {
+        mFlags |= other.mFlags;
+        return *this;
+    }
+    constexpr inline Flags &operator|=(Enum flag) {
+        mFlags |= toUnderlying(flag);
+        return *this;
+    }
+    constexpr inline Flags &operator&=(Flags other) {
+        mFlags &= other.mFlags;
+        return *this;
+    }
+    constexpr inline Flags &operator&=(Enum flag) {
+        mFlags &= toUnderlying(flag);
+        return *this;
+    }
+    constexpr inline Flags &operator^=(Flags other) {
+        mFlags ^= other.mFlags;
+        return *this;
+    }
+    constexpr inline Flags &operator^=(Enum flag) {
+        mFlags ^= toUnderlying(flag);
+        return *this;
+    }
+
+    constexpr inline Flags operator~() const {
+        return Flags(~mFlags & (~std::bitset<_Nb>()).to_ulong());
+    }
+
+    friend constexpr inline bool operator==(const Flags &lhs, const Flags 
&rhs) {
+        return lhs.mFlags == rhs.mFlags;
+    }
+    friend constexpr inline bool operator!=(const Flags &lhs, const Flags 
&rhs) {
+        return !(lhs == rhs);
+    }
+
+private:
+    constexpr inline explicit Flags(UnderlyingT flags)
+        : mFlags(flags)
+    {
+    }
+
+    static constexpr inline UnderlyingT toUnderlying(Enum flag) {
+        return static_cast<UnderlyingT>(flag);
+    }
+
+private:
+    UnderlyingT mFlags = static_cast<UnderlyingT>(0);
+};
+
+#define GPGMEPP_DEFINE_ENUM_FLAG_OPERATORS(FlagsType) \
+constexpr inline FlagsType operator|(FlagsType::enum_type lhs, 
FlagsType::enum_type rhs) \
+{ \
+    return FlagsType{lhs} | rhs; \
+} \
+constexpr inline FlagsType operator&(FlagsType::enum_type lhs, 
FlagsType::enum_type rhs) \
+{ \
+    return FlagsType{lhs} & rhs; \
+} \
+constexpr inline FlagsType operator^(FlagsType::enum_type lhs, 
FlagsType::enum_type rhs) \
+{ \
+    return FlagsType{lhs} ^ rhs; \
+}
+
+template <typename Enum, std::size_t _Nb>
+std::ostream &operator<<(std::ostream &os, const Flags<Enum, _Nb> &flags)
+{
+    // Write out a bitset representation.
+    os << std::bitset<_Nb>(flags.toUnderlyingType());
+    return os;
+}
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_FLAGS_H__
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/global.h 
new/gpgmepp-2.1.0/src/global.h
--- old/gpgmepp-2.0.0/src/global.h      2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/global.h      2026-05-18 12:04:51.000000000 +0200
@@ -26,6 +26,7 @@
 #ifndef __GPGMEPP_GLOBAL_H__
 #define __GPGMEPP_GLOBAL_H__
 
+#include "flags.h"
 #include "gpgmefw.h"
 #include "gpgmepp_export.h"
 
@@ -89,6 +90,14 @@
     NoLongerUsed = 3
 };
 
+enum class DeletionFlag : unsigned int {
+    // Keep in line with GPGME_DELETE_* flags
+    AllowSecret = (1 << 0),
+    Force = (1 << 1),
+};
+using DeletionFlags = Flags<DeletionFlag>;
+GPGMEPP_DEFINE_ENUM_FLAG_OPERATORS(DeletionFlags)
+
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Protocol proto);
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Engine eng);
 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, KeyListMode mode);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/key.cpp 
new/gpgmepp-2.1.0/src/key.cpp
--- old/gpgmepp-2.0.0/src/key.cpp       2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/key.cpp       2026-05-18 12:04:51.000000000 +0200
@@ -611,6 +611,14 @@
     return subkey ? subkey->keygrip : nullptr;
 }
 
+std::vector<std::string_view> Subkey::keyGrips() const
+{
+    if (!subkey || !subkey->keygrip) {
+        return {};
+    }
+    return _gpgmepp::split_into_string_views(subkey->keygrip, ',');
+}
+
 bool Subkey::isSecret() const
 {
     return subkey && subkey->secret;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/key.h new/gpgmepp-2.1.0/src/key.h
--- old/gpgmepp-2.0.0/src/key.h 2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/key.h 2026-05-18 12:04:51.000000000 +0200
@@ -32,6 +32,7 @@
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include <ctime>
@@ -338,8 +339,21 @@
 
     const char *cardSerialNumber() const;
 
+    /*!
+     * Returns the keygrip(s) of the subkey in hex digit form or NULL if not 
available.
+     * For combined algorithms the keygrips are delimited by comma.
+     *
+     * \sa keyGrips
+     */
     const char *keyGrip() const;
 
+    /*!
+     * Returns the list of keygrips of the subkey in hex digit form.
+     *
+     * \note The individual keygrips are not necessarily null-terminated.
+     */
+    std::vector<std::string_view> keyGrips() const;
+
 private:
     shared_gpgme_key_t key;
     gpgme_sub_key_t subkey;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/randomresults.h 
new/gpgmepp-2.1.0/src/randomresults.h
--- old/gpgmepp-2.0.0/src/randomresults.h       2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/src/randomresults.h       2026-05-18 12:04:51.000000000 
+0200
@@ -42,6 +42,10 @@
         : mValue{value}
     {
     }
+    explicit RandomBytesResult(value_type &&value)
+        : mValue{std::move(value)}
+    {
+    }
     explicit RandomBytesResult(const Error &err)
         : Result{err}
     {
@@ -81,6 +85,35 @@
     unsigned int mValue = 0;
 };
 
+class GPGMEPP_EXPORT RandomZBase32StringResult : public Result
+{
+public:
+    RandomZBase32StringResult()
+        : Result{GPG_ERR_NO_VALUE}
+    {
+    }
+    explicit RandomZBase32StringResult(const std::string &value)
+        : mValue{value}
+    {
+    }
+    explicit RandomZBase32StringResult(std::string &&value)
+        : mValue{std::move(value)}
+    {
+    }
+    explicit RandomZBase32StringResult(const Error &err)
+        : Result{err}
+    {
+    }
+
+    const std::string &value() const
+    {
+        return mValue;
+    }
+
+private:
+    std::string mValue;
+};
+
 } // namespace GpgME
 
 #endif /* __GPGMEPP_RANDOMRESULTS_H__ */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/util.cpp 
new/gpgmepp-2.1.0/src/util.cpp
--- old/gpgmepp-2.0.0/src/util.cpp      2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/util.cpp      2026-05-18 12:04:51.000000000 +0200
@@ -29,6 +29,26 @@
 
 #include <functional>
 
+#include <cstring>
+
+std::vector<std::string_view> _gpgmepp::split_into_string_views(const char *s, 
char delimiter)
+{
+    std::vector<std::string_view> result;
+    if (!s) {
+        return result;
+    }
+    while (const char *segment_end = std::strchr(s, delimiter)) {
+        if (const auto segment_size = segment_end - s) {
+            result.emplace_back(s, segment_size);
+        }
+        s = segment_end + 1;
+    };
+    if (const auto segment_size = std::strlen(s)) {
+        result.emplace_back(s, segment_size);
+    }
+    return result;
+}
+
 StringsToCStrings::StringsToCStrings(const std::vector<std::string>& v)
     : m_strings{v}
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/src/util.h new/gpgmepp-2.1.0/src/util.h
--- old/gpgmepp-2.0.0/src/util.h        2025-06-03 15:44:34.000000000 +0200
+++ new/gpgmepp-2.1.0/src/util.h        2026-05-18 12:04:51.000000000 +0200
@@ -190,6 +190,16 @@
     return result;
 }
 
+namespace _gpgmepp {
+
+/*!
+ * Splits \a s into substrings whereever \a delimiter occurs.
+ * Empty substrings are omitted.
+ */
+GPGMEPP_EXPORT std::vector<std::string_view> split_into_string_views(const 
char *s, char delimiter);
+
+} // namespace _gpgmepp
+
 /**
  * Adapter for passing a vector of strings as NULL-terminated array of
  * const char* to the C-interface of gpgme.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/tests/CMakeLists.txt 
new/gpgmepp-2.1.0/tests/CMakeLists.txt
--- old/gpgmepp-2.0.0/tests/CMakeLists.txt      2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/tests/CMakeLists.txt      2026-05-18 12:04:51.000000000 
+0200
@@ -22,12 +22,21 @@
     get_filename_component(_name ${_source} NAME_WE)
     add_executable(${_name} ${_source})
     target_link_libraries(${_name} Gpgmepp)
-    set_target_properties(${_target} PROPERTIES
+    set_target_properties(${_name} PROPERTIES
                           WIN32_EXECUTABLE FALSE # don't build as GUI app on 
Windows
                           MACOSX_BUNDLE FALSE # don't build as GUI app on macOS
     )
 endmacro()
 
+macro(_g10_add_test _source)
+    _g10_add_testprogram(${_source})
+    get_filename_component(_name ${_source} NAME_WE)
+    add_test(NAME ${_name} COMMAND ${_name})
+endmacro()
+
+_g10_add_test(t-flags.cpp)
+_g10_add_test(t-utils.cpp)
+
 _g10_add_testprogram(run-createkey.cpp)
 _g10_add_testprogram(run-genrandom.cpp)
 _g10_add_testprogram(run-getkey.cpp)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/tests/run-genrandom.cpp 
new/gpgmepp-2.1.0/tests/run-genrandom.cpp
--- old/gpgmepp-2.0.0/tests/run-genrandom.cpp   2025-06-03 15:44:34.000000000 
+0200
+++ new/gpgmepp-2.1.0/tests/run-genrandom.cpp   2026-05-18 12:04:51.000000000 
+0200
@@ -143,14 +143,11 @@
             break;
         }
         case ZBase32: {
-            const auto result = ctx->generateRandomBytes(31, 
Context::RandomMode::ZBase32);
+            const auto result = ctx->generateRandomZBase32String();
             if (result.error()) {
                 std::cerr << "Error: Failed to generate random zbase32 
characters: " << result.error().asStdString() << std::endl;
             } else {
-                std::string password;
-                password.reserve(result.value().size());
-                std::copy(result.value().begin(), result.value().end(), 
std::back_inserter(password));
-                std::cout << password << std::endl;
+                std::cout << result.value() << std::endl;
             }
             break;
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/tests/t-flags.cpp 
new/gpgmepp-2.1.0/tests/t-flags.cpp
--- old/gpgmepp-2.0.0/tests/t-flags.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new/gpgmepp-2.1.0/tests/t-flags.cpp 2026-05-18 12:04:51.000000000 +0200
@@ -0,0 +1,240 @@
+/*
+    t-flags.cpp
+
+    This file is part of GPGME++'s test suite.
+    Copyright (c) 2025 g10 Code GmbH
+    Software engineering by Ingo Klöcker <[email protected]>
+
+    GPGME++ is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    GPGME++ 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 Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with GPGME++; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "flags.h"
+
+#include <iostream>
+#include <sstream>
+
+static void
+print_error_and_exit(std::string_view message, std::string_view file, int line)
+{
+    std::cerr << file << ':' << line << ": " << message << std::endl;
+    exit(1);
+}
+
+template<typename T>
+static void
+compare_helper(T actualValue, T expectedValue, std::string_view expression, 
std::string_view expected, std::string_view filename, int line)
+{
+    if (actualValue != expectedValue) {
+        std::stringstream stream;
+        stream << "Expression is not equal to " << expected << ": " << 
expression << std::endl;
+        stream << "expected: " << expectedValue << std::endl;
+        stream << "actual  : " << actualValue << std::endl;
+        print_error_and_exit(stream.str(), filename, line);
+    }
+}
+
+#define ASSERT_TRUE(expression) do { if (!(expression)) { 
print_error_and_exit("Expression is not true: " #expression, __FILE__, 
__LINE__); } } while (false)
+#define ASSERT_FALSE(expression) do { if ((expression)) { 
print_error_and_exit("Expression is not false: " #expression, __FILE__, 
__LINE__); } } while (false)
+#define ASSERT_EQUAL(expression, expected) do { compare_helper(expression, 
expected, #expression, #expected, __FILE__, __LINE__); } while (false)
+
+enum class TestFlag : unsigned int {
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+};
+using TestFlags = GpgME::Flags<TestFlag, 3>;
+
+static void
+test_construction()
+{
+    {
+        const TestFlags flags;
+        ASSERT_EQUAL(flags.toUnderlyingType(), 0u);
+        ASSERT_TRUE(!flags);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+    }
+    {
+        const TestFlags flags{TestFlag::A};
+        ASSERT_EQUAL(flags.toUnderlyingType(), 1u);
+        ASSERT_TRUE(flags);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+    }
+    {
+        const TestFlags flags{TestFlag::B, TestFlag::C};
+        ASSERT_EQUAL(flags.toUnderlyingType(), 6u);
+        ASSERT_TRUE(flags);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_TRUE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+    }
+    {
+        const TestFlags flags = TestFlags::fromUnderlyingType(3u);
+        ASSERT_EQUAL(flags.toUnderlyingType(), 3u);
+        ASSERT_TRUE(flags);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_TRUE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+    }
+}
+
+static void
+test_set_reset()
+{
+    {
+        TestFlags flags;
+        flags.set(TestFlag::A);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+        flags.set(TestFlag::C);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+        flags.set(TestFlag::B);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_TRUE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+        flags.set(TestFlag::A, false);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_TRUE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+    }
+    {
+        TestFlags flags{TestFlag::A, TestFlag::B, TestFlag::C};
+        flags.reset(TestFlag::B);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+        flags.reset();
+        ASSERT_TRUE(!flags);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+    }
+    {
+        TestFlags flags;
+        flags.set(TestFlag::A).set(TestFlag::B);
+        ASSERT_TRUE(flags.test(TestFlag::A));
+        ASSERT_TRUE(flags.test(TestFlag::B));
+        ASSERT_FALSE(flags.test(TestFlag::C));
+    }
+    {
+        TestFlags flags;
+        
flags.set(TestFlag::A).set(TestFlag::B).reset(TestFlag::A).set(TestFlag::B, 
false).set(TestFlag::C);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+    }
+    {
+        TestFlags flags;
+        flags.set(TestFlag::A).set(TestFlag::B).reset().set(TestFlag::C);
+        ASSERT_FALSE(flags.test(TestFlag::A));
+        ASSERT_FALSE(flags.test(TestFlag::B));
+        ASSERT_TRUE(flags.test(TestFlag::C));
+    }
+}
+
+static void
+test_operators()
+{
+    const TestFlags flagsA{TestFlag::A};
+    const TestFlags flagsB{TestFlag::B};
+    const TestFlags flagsC{TestFlag::C};
+    const TestFlags flagsAB{TestFlag::A, TestFlag::B};
+    const TestFlags flagsAC{TestFlag::A, TestFlag::C};
+    const TestFlags flagsBC{TestFlag::B, TestFlag::C};
+    const TestFlags flagsABC{TestFlag::A, TestFlag::B, TestFlag::C};
+    {
+        ASSERT_EQUAL(flagsA | flagsB, flagsAB);
+        ASSERT_EQUAL(flagsA | TestFlag::B, flagsAB);
+        ASSERT_EQUAL(TestFlag::A | flagsB, flagsAB);
+        TestFlags flags = flagsA;
+        flags |= flagsB;
+        ASSERT_EQUAL(flags, flagsAB);
+        flags |= TestFlag::C;
+        ASSERT_EQUAL(flags, flagsABC);
+    }
+    {
+        ASSERT_EQUAL(flagsAB & flagsB, flagsB);
+        ASSERT_EQUAL(flagsAB & TestFlag::B, flagsB);
+        ASSERT_EQUAL(TestFlag::B & flagsAB, flagsB);
+        TestFlags flags = flagsABC;
+        flags &= flagsBC;
+        ASSERT_EQUAL(flags, flagsBC);
+        flags &= TestFlag::C;
+        ASSERT_EQUAL(flags, flagsC);
+    }
+    {
+        ASSERT_EQUAL(flagsAB ^ flagsAC, flagsBC);
+        ASSERT_EQUAL(flagsAB ^ TestFlag::B, flagsA);
+        ASSERT_EQUAL(TestFlag::B ^ flagsAB, flagsA);
+        TestFlags flags = flagsAB;
+        flags ^= flagsAC;
+        ASSERT_EQUAL(flags, flagsBC);
+        flags ^= TestFlag::C;
+        ASSERT_EQUAL(flags, flagsB);
+    }
+    {
+        TestFlags flags = ~flagsAB;
+        ASSERT_FALSE(flags & flagsA);
+        ASSERT_FALSE(flags & flagsB);
+        ASSERT_TRUE(flags & flagsC);
+    }
+    {
+        TestFlags flags = ~flagsABC;
+        ASSERT_FALSE(flags & flagsA);
+        ASSERT_FALSE(flags & flagsB);
+        ASSERT_FALSE(flags & flagsC);
+        ASSERT_FALSE(flags);
+    }
+    {
+        ASSERT_TRUE(flagsAB != flagsBC);
+        ASSERT_FALSE(flagsAB != flagsAB);
+    }
+}
+
+GPGMEPP_DEFINE_ENUM_FLAG_OPERATORS(TestFlags)
+
+static void
+test_additional_flag_operators()
+{
+    const TestFlags flagsA{TestFlag::A};
+    const TestFlags flagsAB{TestFlag::A, TestFlag::B};
+    ASSERT_EQUAL(TestFlag::A | TestFlag::A, flagsA);
+    ASSERT_EQUAL(TestFlag::A | TestFlag::B, flagsAB);
+    ASSERT_EQUAL(TestFlag::A & TestFlag::A, flagsA);
+    ASSERT_EQUAL(TestFlag::A & TestFlag::B, TestFlags());
+    ASSERT_EQUAL(TestFlag::A ^ TestFlag::A, TestFlags());
+    ASSERT_EQUAL(TestFlag::A ^ TestFlag::B, flagsAB);
+}
+
+int
+main (int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    test_construction();
+    test_set_reset();
+    test_operators();
+    test_additional_flag_operators();
+
+    return 0;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gpgmepp-2.0.0/tests/t-utils.cpp 
new/gpgmepp-2.1.0/tests/t-utils.cpp
--- old/gpgmepp-2.0.0/tests/t-utils.cpp 1970-01-01 01:00:00.000000000 +0100
+++ new/gpgmepp-2.1.0/tests/t-utils.cpp 2026-05-18 12:04:51.000000000 +0200
@@ -0,0 +1,106 @@
+/*
+    t-utils.cpp
+
+    This file is part of GPGME++'s test suite.
+    Copyright (c) 2025 g10 Code GmbH
+    Software engineering by Ingo Klöcker <[email protected]>
+
+    GPGME++ is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    GPGME++ 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 Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with GPGME++; see the file COPYING.LIB.  If not, write to the
+    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "global.h"
+#include "util.h"
+
+#include <iostream>
+
+using namespace _gpgmepp;
+
+static void
+print_error_and_exit(std::string_view message, std::string_view file, int line)
+{
+    std::cerr << file << ':' << line << ": " << message << std::endl;
+    exit(1);
+}
+
+static void
+test_split_into_string_views()
+{
+    {
+        const auto result = split_into_string_views(nullptr, ',');
+        if (!result.empty()) {
+            print_error_and_exit("result not empty", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views("", ',');
+        if (!result.empty()) {
+            print_error_and_exit("result not empty", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views("abc", ',');
+        if ((result.size() != 1) || (result[0] != "abc")) {
+            print_error_and_exit("unexpected result", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views("abc,def", ',');
+        if ((result.size() != 2) || (result[0] != "abc") || (result[1] != 
"def")) {
+            print_error_and_exit("unexpected result", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views(",abc", ',');
+        if ((result.size() != 1) || (result[0] != "abc")) {
+            print_error_and_exit("unexpected result", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views("abc,", ',');
+        if ((result.size() != 1) || (result[0] != "abc")) {
+            print_error_and_exit("unexpected result", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views("abc,,def", ',');
+        if ((result.size() != 2) || (result[0] != "abc") || (result[1] != 
"def")) {
+            print_error_and_exit("unexpected result", __FILE__, __LINE__);
+        }
+    }
+    {
+        const auto result = split_into_string_views(",", ',');
+        if (!result.empty()) {
+            print_error_and_exit("result not empty", __FILE__, __LINE__);
+        }
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+    (void)argc;
+    (void)argv;
+
+    GpgME::initializeLibrary();
+
+    test_split_into_string_views();
+
+    return 0;
+}

++++++ gpgmepp.keyring ++++++
--- /var/tmp/diff_new_pack.gp8Szq/_old  2026-06-01 17:58:49.801443477 +0200
+++ /var/tmp/diff_new_pack.gp8Szq/_new  2026-06-01 17:58:49.829444638 +0200
@@ -77,7 +77,19 @@
 IPBELwEAq1lsS4pO0+WCQtSAyV5Nxkn+8SEkT4a99D2jmBYKoQWIdQQQFgoAHRYh
 BMHTS2khnkruwLocIeP9/yGORbcrBQJhaU9aAAoJEOP9/yGORbcrHh4BAOnpoZI3
 99TjEuXxFK9BRWNUD5oJOsxBHeFHCrDyWIXbAQDc7cQLHPp7X4Ogi1igkEEsovB6
-IiewZn/6HldiuldOAA==
-=gHNs
+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
 -----END PGP PUBLIC KEY BLOCK-----
 

Reply via email to