Compare commits

..

6 Commits

Author SHA1 Message Date
Daniel Kahn Gillmor
ac8d7238db python: overhaul logic of Context.decrypt()
* lang/python/src/core.py (Context.decrypt): simplify and clarify the
logic behind handling verify=False.
* lang/python/tests/t-decrypt.py: ensure that we test verify=False

--

The function-internal variables were pretty unclear to the reader, and
the logic caused pretty nasty breakage when verify=False.

GnuPG-Bug-Id: 4271
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:41:16 +03:00
Daniel Kahn Gillmor
5e21e61cfe python: ctx.decrypt() has problematic error handling
* lang/python/src/core.py (Context.decrypt): document odd
error-handling behavior as a potential problem to be addressed.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:25 +03:00
Daniel Kahn Gillmor
fefa46173e python: Clarify the meaning of ctx.decrypt(verify=[])
* lang/python/src/core.py (Context.decrypt): docstring clarification
of what it means to pass an empty list to the verify argument.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
30ddb2cabc python: gpg.Context.decrypt verify_sigs and sink_result are bools
Both of these function-internal variables are never used for anything
other than a binary state.  Implement them as the booleans they are.
Otherwise, casual readers of the code might think that they're
supposed to represent something other than a flag (e.g. "verify_sigs"
could mean "the signatures to verify", and "sink_result" could mean
"the place where we sink the result").

Signed-Off-By: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
9a1903cc42 python: clarify documentation for verify argument for Context.decrypt()
It's easy to miss that verify can take a list of keys.  Make it more
obvious to the average python dev who reads docstrings.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
827a2f3ad5 python: simplify Context.decrypt()
In the course of trying to address https://dev.gnupg.org/T4271, i
discovered that gpg.Context.decrypt() has a bit of superfluous code.
This changeset is intended to simplify the code without making any
functional changes.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
510 changed files with 15049 additions and 32588 deletions

16
AUTHORS
View File

@ -9,24 +9,20 @@ License (software): LGPL-2.1-or-later
License (manual+tools): GPL-3.0-or-later
GPGME is free software. See the files COPYING.LESSER and COPYING for
copying conditions, , and LICENSES for notices about contributions
that require these additional notices to be distributed. License
copyright years may be listed using range notation, e.g., 2000-2013,
indicating that every year in the range, inclusive, is a copyrightable
year that would otherwise be listed individually.
GPGME is free software. See the files COPYING for copying conditions.
License copyright years may be listed using range notation, e.g.,
2000-2013, indicating that every year in the range, inclusive, is a
copyrightable year that would otherwise be listed individually.
List of Copyright holders
=========================
Copyright (C) 1991-2013 Free Software Foundation, Inc.
Copyright (C) 2000-2001 Werner Koch
Copyright (C) 2001-2023 g10 Code GmbH
Copyright (C) 2001-2018 g10 Code GmbH
Copyright (C) 2002 Klarälvdalens Datakonsult AB
Copyright (C) 2004-2008 Igor Belyi
Copyright (C) 2002 John Goerzen
Copyright (c) 2009 Dave Gamble
Copyright (C) 2014, 2015 Martin Albrecht
Copyright (C) 2015, 2018 Ben McGinnes
Copyright (C) 2015, 2016, 2018
@ -43,7 +39,7 @@ FSF <gnu@gnu.org>
src/stpcpy.c, src/w32-ce.c.
g10 Code GmbH <code@g10code.com>
- All stuff since mid March 2001.
- All stuff since mid march 2001.
Werner Koch <wk@gnupg.org>
- Design and most stuff.

View File

@ -1,38 +0,0 @@
Additional license notices for GPGME. -*- org -*-
This file contains the copying permission notices for various files in
the GPGME distribution which are not covered by the GNU Lesser
General Public License (LGPL) or the GNU General Public License (GPL).
These notices all require that a copy of the notice be included
in the accompanying documentation and be distributed with binary
distributions of the code, so be sure to include this file along
with any binary distributions derived from the GNU C Library.
* MIT License
For files:
- cJSON.c, cJSON.h
#+begin_quote
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining
a opy of this software and associated documentation files (the
"Software"), to eal in the Software without restriction, including
without limitation the ights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software 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 Software.
THE SOFTWARE IS 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 ROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#+end_quote

View File

@ -20,14 +20,14 @@
## Process this file with automake to produce Makefile.in
# Location of the released tarball archives. This is prefixed by
# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example:
# RELEASE_ARCHIVE=user@host:archive/tarballs
RELEASE_ARCHIVE_SUFFIX = gpgme
# The variable RELEASE_SIGNKEY in ~/.gnupg-autogen.rc is used
# to specify the key for signing. For example:
# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
# Location of the released tarball archives. Note that this is an
# internal archive and before uploading this to the public server,
# manual tests should be run and the git release tat set and pushed.
# Adjust as needed.
RELEASE_ARCHIVE_DIR = wk@vigenere:tarballs/gpgme/
# The key used to sign the released sources. Adjust as needed.
RELEASE_SIGNING_KEY = D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
# Autoconf flags
ACLOCAL_AMFLAGS = -I m4
@ -36,11 +36,8 @@ DISTCHECK_CONFIGURE_FLAGS =
EXTRA_DIST = autogen.sh autogen.rc gpgme.spec.in \
ChangeLog-2011 m4/ChangeLog-2011 \
build-aux/libtool-patch.sed \
conf/whatisthis VERSION LICENSES
conf/whatisthis VERSION
# This artificial line is to put a dependency to conf/config.h for 'all'
BUILT_SOURCES = conf/config.h
if RUN_GPG_TESTS
tests = tests
@ -100,7 +97,7 @@ release:
cd $(abs_top_builddir); \
rm -rf dist; mkdir dist ; cd dist ; \
$(abs_top_srcdir)/configure --enable-maintainer-mode; \
$(MAKE) distcheck; \
$(MAKE) distcheck TESTFLAGS=--parallel; \
echo "/* Build finished at $$(date -uIseconds) */" ;\
echo "/*" ;\
echo " * Please run the final step interactively:" ;\
@ -110,32 +107,20 @@ release:
sign-release:
+(set -e; \
test $$(pwd | sed 's,.*/,,') = dist || cd dist; \
x=$$(grep '^RELEASE_ARCHIVE=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
if [ -z "$$x" ]; then \
echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \
exit 2;\
fi;\
myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\
x=$$(grep '^RELEASE_SIGNKEY=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
if [ -z "$$x" ]; then \
echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \
exit 2;\
fi;\
mysignkey="$$x";\
cd dist; \
files1="$(RELEASE_NAME).tar.bz2" ;\
files2="$(RELEASE_NAME).tar.bz2.sig \
$(RELEASE_NAME).swdb \
$(RELEASE_NAME).buildlog" ;\
echo "/* Signing the source tarball ..." ;\
gpg -sbu $$mysignkey $(RELEASE_NAME).tar.bz2 ;\
gpg -sbu $(RELEASE_SIGNING_KEY) $(RELEASE_NAME).tar.bz2 ;\
cat $(RELEASE_NAME).swdb >swdb.snippet;\
echo >>swdb.snippet ;\
sha1sum $${files1} >>swdb.snippet ;\
cat "../$(RELEASE_NAME).buildlog" swdb.snippet \
| gzip >$(RELEASE_NAME).buildlog ;\
echo "Copying to local archive ..." ;\
scp -p $${files1} $${files2} $$myarchive/ || true;\
scp -p $${files1} $${files2} $(RELEASE_ARCHIVE_DIR)/ || true;\
echo "Uploading documentation ..." ;\
$(MAKE) -C doc online; \
echo '/*' ;\

756
NEWS
View File

@ -1,767 +1,13 @@
Noteworthy changes in version 1.24.0 (unrelease)
Noteworthy changes in version 1.12.1 (unreleased)
-------------------------------------------------
* Extended gpgme_op_decrypt* and gpgme_op_verify* to allow writing the
output directly to a file. [T6550]
* Extended gpgme_op_encrypt*, gpgme_op_encrypt_sign*, and gpgme_op_sign*
to allow reading the input data directly from a file. [T6550]
* Add information about designated revocation keys. [T7118]
* New context flag "import-options". [T7152]
* cpp: Provide information about designated revocation keys for a Key.
[T7118]
* cpp: Add safer member function returning text describing an error.
[T5960]
* qt: Build QGpgME for Qt 5 and Qt 6 simultaneously. [T7205]
* qt: Install headers for Qt 5 and Qt 6 in separate folders. [T7161]
* qt: Allow reading the data to decrypt/encrypt/sign/verify directly from
files. [T6550]
* qt: Allow writing the decrypted/encrypted/signed/verified data directly
to files. [T6550]
* qt: Allow specifying import options when importing keys. [T7152]
* qt: Allow appending a detached signature to an existing file. [T6867]
* Interface changes relative to the 1.23.2 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_ENCRYPT_FILE NEW.
GPGME_SIG_MODE_FILE NEW.
gpgme_key_t EXTENDED: New field 'revkeys'.
gpgme_revocation_key_t NEW.
gpgme_set_ctx_flag EXTENDED: New flag 'import-options'.
cpp: Context::EncryptFile NEW.
cpp: SignatureMode::SignFile NEW.
cpp: RevocationKey NEW.
cpp: Key::revocationKey NEW.
cpp: Key::numRevocationKeys NEW.
cpp: Key::revocationKeys NEW.
cpp: Error::asStdString NEW.
cpp: Error::asString DEPRECATED.
qt: DecryptVerifyJob::setInputFile NEW.
qt: DecryptVerifyJob::inputFile NEW.
qt: DecryptVerifyJob::setOutputFile NEW.
qt: DecryptVerifyJob::outputFile NEW.
qt: EncryptJob::setRecipients NEW.
qt: EncryptJob::recipients NEW.
qt: EncryptJob::setInputFile NEW.
qt: EncryptJob::inputFile NEW.
qt: EncryptJob::setOutputFile NEW.
qt: EncryptJob::outputFile NEW.
qt: EncryptJob::setEncryptionFlags NEW.
qt: EncryptJob::encryptionFlags NEW.
qt: SignEncryptJob::setSigners NEW.
qt: SignEncryptJob::signers NEW.
qt: SignEncryptJob::setRecipients NEW.
qt: SignEncryptJob::recipients NEW.
qt: SignEncryptJob::setInputFile NEW.
qt: SignEncryptJob::inputFile NEW.
qt: SignEncryptJob::setOutputFile NEW.
qt: SignEncryptJob::outputFile NEW.
qt: SignEncryptJob::setEncryptionFlags NEW.
qt: SignEncryptJob::encryptionFlags NEW.
qt: SignJob::setSigners NEW.
qt: SignJob::signers NEW.
qt: SignJob::setInputFile NEW.
qt: SignJob::inputFile NEW.
qt: SignJob::setOutputFile NEW.
qt: SignJob::outputFile NEW.
qt: SignJob::setSigningFlags NEW.
qt: SignJob::signingFlags NEW.
qt: SignJob::setAppendSignature NEW.
qt: SignJob::appendSignatureEnabled NEW.
qt: VerifyDetachedJob::setSignatureFile NEW.
qt: VerifyDetachedJob::signatureFile NEW.
qt: VerifyDetachedJob::setSignedFile NEW.
qt: VerifyDetachedJob::signedFile NEW.
qt: VerifyOpaqueJob::setInputFile NEW.
qt: VerifyOpaqueJob::inputFile NEW.
qt: VerifyOpaqueJob::setOutputFile NEW.
qt: VerifyOpaqueJob::outputFile NEW.
qt: ImportJob::setImportOptions NEW.
qt: ImportJob::importOptions NEW.
Noteworthy changes in version 1.23.2 (2023-11-28)
-------------------------------------------------
* Preserve more specific existing failure code. [T6575]
* qt: Start dirmngr with gpgconf to avoid multiple instances. [T6833]
* qt: On Windows, use UTF-8 when logging the error text. [T5960]
* qt: Remove left-over partial files more persistently. [T6584]
* qt: Use a temporary file name when creating signed or encrypted
archives. [T6721]
* qt: Build Qt 6 bindings with -fPIC if requested or Qt 6 was built with
this flag. [T6781]
Notes:
~~~~~~
qt: DefaultKeyGenerationJob DEPRECATED.
[c=C43/A32/R1 cpp=C26/A20/R1 qt=C20/A5/R1]
Release-info: https://dev.gnupg.org/T6782
Noteworthy changes in version 1.23.1 (2023-10-27)
-------------------------------------------------
* w32: Change gpgme-w32-spawn to use Unicode arguments. [T6728]
[c=C43/A32/R0 cpp=C26/A20/R0 qt=C20/A5/R0]
Release-info: https://dev.gnupg.org/T6774
Noteworthy changes in version 1.23.0 (2023-10-25)
-------------------------------------------------
* Support GPGME_ENCRYPT_ALWAYS_TRUST also for S/MIME. [T6559]
* New keylist mode GPGME_KEYLIST_MODE_WITH_V5FPR. [T6705]
* New key capability flags has_*. [T6748]
* gpgme-tool: Support use of Windows HANDLE. [T6634]
* qt: Support refreshing keys via WKD. [T6672]
* qt: Handle cancel in changeexpiryjob. [T6754]
* Interface changes relative to the 1.22.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_WITH_V5FPR NEW.
gpgme_key_t EXTENDED: New field has_encrypt.
gpgme_key_t EXTENDED: New field has_sign.
gpgme_key_t EXTENDED: New field has_certify.
gpgme_key_t EXTENDED: New field has_authenticate.
cpp: Key::canCertify NEW.
cpp: Key::canSign NEW.
cpp: Key::canEncrypt NEW.
cpp: Key::canAuthenticate NEW.
qt: Protocol::wkdRefreshJob NEW.
qt: WKDRefreshJob NEW.
[c=C43/A32/R0 cpp=C26/A20/R0 qt=C20/A5/R0]
Release-info: https://dev.gnupg.org/T6774
Noteworthy changes in version 1.22.0 (2023-08-21)
-------------------------------------------------
* Prevent wrong plaintext when verifying clearsigned signature. [T6622]
* Return bad data error instead of general error on unexpected data.
[T6617]
* Take care of offline mode for all operations of gpgsm engine.
[T6648]
* Prepare the use of the forthcoming libassuan version 3.
* New configure option --with-libtool-modification. [T6619]
* cpp: Expose gpgme_decrypt_result_t.is_mime. [T6199]
* qt: Clean up after failure or cancel of sign/encrypt archive
operation. [T6584]
* qt: Add setInputEncoding to QGpgMe::EncryptJob. [T6166]
* qt: Make toLogString helper public. [T6584]
* Interface changes relative to the 1.21.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
qt: EncryptJob::setInputEncoding NEW.
qt: DecryptionResult::isMime NEW.
qt: toLogString NEW.
[c=C42/A31/R0 cpp=C25/A19/R0 qt=C19/A4/R0]
Release-info: https://dev.gnupg.org/T6668
Noteworthy changes in version 1.21.0 (2023-07-07)
-------------------------------------------------
* Extended gpgme_op_encrypt, gpgme_op_encrypt_sign, and gpgme_op_sign
to allow writing the output directly to a file. [T6530]
* Extended gpgme_op_decrypt and gpgme_op_verify to allow reading the
input data directly from files. [T6530]
* For key signing and uid revoking allow an empty user id.
[rMfbc3963d62]
* Pass an input-size-hint also to the gpgsm engine. [T6534]
* qt: Allow writing the created archives directly to a
file. [T6530]
* qt: Allow reading the signed/encrypted archive to decrypt
or verify directly from a file. [T6530]
* qt: Qt Jobs working with QIODeviceDataProvider now properly
handle input-size hints and progress for files larger.
2^32 bytes in 32 bit builds. [T6534]
* cpp: Error::isCanceled now also returns true for error code
GPG_ERR_FULLY_CANCELED. [T6510]
* python: Fix wrong use of write. [T6501]
* Interface changes relative to the 1.20.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cpp: Data::setFlag NEW.
cpp: Data::setSizeHint NEW.
qt: Job::startIt NEW.
qt: DecryptVerifyArchiveJob::setInputFile NEW.
qt: DecryptVerifyArchiveJob::inputFile NEW.
qt: EncryptArchiveJob::setRecipients NEW.
qt: EncryptArchiveJob::recipients NEW.
qt: EncryptArchiveJob::setInputPaths NEW.
qt: EncryptArchiveJob::inputPaths NEW.
qt: EncryptArchiveJob::setOutputFile NEW.
qt: EncryptArchiveJob::outputFile NEW.
qt: EncryptArchiveJob::setEncryptionFlags NEW.
qt: EncryptArchiveJob::encryptionFlags NEW.
qt: SignArchiveJob::setSigners NEW.
qt: SignArchiveJob::signers NEW.
qt: SignArchiveJob::setInputPaths NEW.
qt: SignArchiveJob::inputPaths NEW.
qt: SignArchiveJob::setOutputFile NEW.
qt: SignArchiveJob::outputFile NEW.
qt: SignEncryptArchiveJob::setSigners NEW.
qt: SignEncryptArchiveJob::signers NEW.
qt: SignEncryptArchiveJob::setRecipients NEW.
qt: SignEncryptArchiveJob::recipients NEW.
qt: SignEncryptArchiveJob::setInputPaths NEW.
qt: SignEncryptArchiveJob::inputPaths NEW.
qt: SignEncryptArchiveJob::setOutputFile NEW.
qt: SignEncryptArchiveJob::outputFile NEW.
qt: SignEncryptArchiveJob::setEncryptionFlags NEW.
qt: SignEncryptArchiveJob::encryptionFlags NEW.
[c=C41/A30/R0 cpp=C24/A18/R0 qt=C18/A3/R0]
Release-info: https://dev.gnupg.org/T6585
Noteworthy changes in version 1.20.0 (2023-04-20)
-------------------------------------------------
* On Windows, the gettext functions provided by gpgrt are switched
into utf8 mode, so that all localized texts returned by GpgME or
gpgrt, e.g. the texts for error codes are now UTF-8 encoded.
[T5960]
* Key::canSign now returns false for OpenPGP keys without signing
(sub)key. [T6456]
* The new macOS Homebrew location is now by default supported.
[T6440]
* Fix regression in 1.19.0. [rMb608c084b9]
* Fix invocation of gpgtar on Windows. [rM0c29119e06]
* Interface changes relative to the 1.19.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_subkey_t EXTENDED: New field 'can_renc'.
gpgme_subkey_t EXTENDED: New field 'can_timestamp'.
gpgme_subkey_t EXTENDED: New field 'is_group_owned'.
cpp: Subkey::canRenc NEW.
cpp: Subkey::canTimestamp NEW.
cpp: Subkey::isGroupOwned NEW.
cpp: Key::canReallySign DEPRECATED.
[c=C40/A29/R0 cpp=C23/A17/R0 qt=C17/A2/R1]
Release-info: https://dev.gnupg.org/T6463
Noteworthy changes in version 1.19.0 (2023-03-17)
-------------------------------------------------
* New convenience option --identify for gpgme-json.
* New context flag "no-auto-check-trustdb". [T6261]
* Optionally, build QGpgME for Qt 6
* Support component "gpgtar-name" in gpgme_get_dirinfo. [T6342]
* Extended gpgme_op_encrypt*, gpgme_op_encrypt_sign*, and
gpgme_op_sign* to allow creating an encrypted and/or signed
archive. [T6342]
* Extended gpgme_op_decrypt*, gpgme_op_decrypt_verify*, and gpgme_op_verify*
to allow extracting an encrypted and/or signed archive. [T6342]
* cpp: Handle error when trying to sign expired keys. [T6155]
* cpp: Support encryption flags ThrowKeyIds, EncryptWrap, and WantAddress.
[T6359]
* cpp, qt: Fix building with C++11. [T6141]
* qt: Fix problem with expiration dates after 2038-01-19 on 32-bit systems
when adding an existing subkey to another key. [T6137]
* cpp: Allow setting the curve to use when generating ECC keys
for smart cards. [T4429]
* qt: Extend ListAllKeysJob to allow disabling the automatic trust database
check when listing all keys. [T6261]
* qt: Allow deferred start of import jobs. [T6323]
* qt: Support creating and extracting signed and encrypted archives. [T6342]
* Interface changes relative to the 1.18.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_get_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'.
gpgme_set_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'.
GPGME_DECRYPT_ARCHIVE NEW.
GPGME_ENCRYPT_ARCHIVE NEW.
GPGME_SIG_MODE_ARCHIVE NEW.
GPGME_VERIFY_ARCHIVE NEW.
gpgme_verify_flags_t NEW.
gpgme_op_verify_ext_start NEW.
gpgme_op_verify_ext NEW.
cpp: GpgGenCardKeyInteractor::Curve NEW.
cpp: GpgGenCardKeyInteractor::setCurve NEW.
cpp: Context::WantAddress NEW.
cpp: Context::DecryptArchive NEW.
cpp: Context::EncryptArchive NEW.
cpp: SignArchive NEW.
cpp: Data::setFileName EXTENDED: New overload
qt: ListAllKeysJob::Option NEW.
qt: ListAllKeysJob::Options NEW.
qt: ListAllKeysJob::setOptions NEW.
qt: ListAllKeysJob::options NEW.
qt: Job::startNow NEW.
qt: ImportJob::startLater NEW.
qt: FileListDataProvider NEW.
qt: DecryptVerifyArchiveJob NEW.
qt: EncryptArchiveJob NEW.
qt: SignArchiveJob NEW.
qt: SignEncryptArchiveJob NEW.
qt: Protocol::decryptVerifyArchiveJob NEW.
qt: Protocol::encryptArchiveJob NEW.
qt: Protocol::signArchiveJob NEW.
qt: Protocol::signEncryptArchiveJob NEW.
qt: Job::jobProgress NEW.
qt: Job::rawProgress NEW.
qt: Job::progress DEPRECATED.
[c=C39/A28/R0 cpp=C22/A16/R0 qt=C17/A2/R0]
Release-info: https://dev.gnupg.org/T6341
Noteworthy changes in version 1.18.0 (2022-08-10)
-------------------------------------------------
* New keylist mode to force refresh via external methods. [T5951]
* The keylist operations now create an import result to report the
result of the locate keylist modes. [T5951]
* core: Return BAD_PASSPHRASE error code on symmetric decryption
failure. [T5939]
* cpp, qt: Do not export internal symbols anymore. [T5906]
* cpp, qt: Support revocation of own OpenPGP keys. [T5904]
* qt: The file name of (signed and) encrypted data can now be set. [T6056]
* cpp, qt: Support setting the primary user ID. [T5938]
* python: Fix segv(NULL) when inspecting contect after exeception. [T6060]
* Interface changes relative to the 1.17.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_FORCE_EXTERN NEW.
GPGME_KEYLIST_MODE_LOCATE_EXTERNAL NEW.
cpp: RevocationReason NEW.
cpp: GpgRevokeKeyEditInteractor NEW.
cpp: Result::setError NEW.
cpp: KeyListMode::ForceExtern NEW.
cpp: KeyListMode::LocateExternal NEW.
cpp: KeyListMode::KeyListModeMask NEW.
cpp: ImportResult::mergeWith NEW.
cpp: KeyListModeSaver NEW.
cpp: Context::setPrimaryUid NEW.
cpp: Context::startSetPrimaryUid NEW.
qt: RevokeKeyJob NEW.
qt: Protocol::revokeKeyJob NEW.
qt: EncryptJob::setFileName NEW.
qt: EncryptJob::fileName NEW.
qt: SignEncryptJob::setFileName NEW.
qt: SignEncryptJob::fileName NEW.
qt: SetPrimaryUserIDJob NEW.
qt: Protocol::setPrimaryUserIDJob NEW.
[c=C38/A27/R0 cpp=C21/A15/R0 qt=C16/A1/R0]
Release-info: https://dev.gnupg.org/T6128
Noteworthy changes in version 1.17.1 (2022-03-06)
-------------------------------------------------
* qt: Fix a bug in the ABI compatibility of 1.17.0. [T5834]
[c=C37/A26/R0 cpp=C20/A14/R0 qt=C15/A0/R0]
Release-info: https://dev.gnupg.org/T5872
Noteworthy changes in version 1.17.0 (2022-02-07)
-------------------------------------------------
* New context flag "key-origin". [#5733]
* New context flag "import-filter". [#5739]
* New export mode to export secret subkeys. [#5757]
* Detect errors during the export of secret keys. [#5766]
* New function gpgme_op_receive_keys to import keys from a keyserver
without first running a key listing. [#5808]
* Detect bad passphrase error in certificate import. [T5713]
* Allow setting --key-origin when importing keys. [T5733]
* Support components "keyboxd", "gpg-agent", "scdaemon", "dirmngr",
"pinentry", and "socketdir" in gpgme_get_dirinfo. [T5727,T5613]
* Under Unix use poll(2) instead of select(2), when available.
[T2385]
* Do not use --flat_namespace when linking for macOS. [T5610]
* Fix results returned by gpgme_data_* functions. [T5481]
* Support closefrom also for glibc. [rM4b64774b6d]
* cpp,qt: Add support for export of secret keys and secret subkeys.
[#5757]
* cpp,qt: Support for adding existing subkeys to other keys. [#5770]
* qt: Extend ChangeExpiryJob to change expiration of primary key
and of subkeys at the same time. [#4717]
* qt: Support WKD lookup without implicit import. [#5728]
* qt: Allow specifying an import filter when importing keys. [#5739]
* qt: Expect UTF-8 on stderr on Windows. [rM8fe1546282]
* qt: Allow retrieving the default value of a config entry. [T5515]
* Interface changes relative to the 1.16.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_op_receive_keys NEW.
gpgme_op_receive_keys_start NEW.
qt: Protocol::secretSubkeyExportJob NEW.
cpp: Context::exportSecretSubkeys NEW.
cpp: Context::startSecretSubkeyExport NEW.
qt: Protocol::secretKeyExportJob CHANGED: Param 'charset' is ignored.
cpp: Context::exportKeys NEW.
cpp: Context::startKeyExport NEW.
cpp: Context::exportSecretKeys NEW.
cpp: Context::startSecretKeyExport NEW.
cpp: GpgAddExistingSubkeyEditInteractor NEW.
GPGME_EXPORT_MODE_SECRET_SUBKEY NEW.
gpgme_set_ctx_flag EXTENDED: New flag 'key-origin'.
gpgme_set_ctx_flag EXTENDED: New flag 'import-filter'.
qt: ChangeExpiryJob::Option NEW.
qt: ChangeExpiryJob::Options NEW.
qt: ChangeExpiryJob::setOptions NEW.
qt: ChangeExpiryJob::options NEW.
qt: CryptoConfigEntry::defaultValue NEW.
qt: WKDLookupJob NEW.
qt: WKDLookupResult NEW.
qt: Protocol::wkdLookupJob NEW.
qt: ImportJob::setKeyOrigin NEW.
qt: ImportJob::keyOrigin NEW.
qt: ImportJob::keyOriginUrl NEW.
qt: setImportFilter NEW.
qt: importFilter NEW.
qt: AddExistingSubkeyJob NEW.
qt: Protocol::addExistingSubkeyJob NEW.
[c=C37/A26/R0 cpp=C20/A14/R0 qt=C14/A7/R0]
Release-info: https://dev.gnupg.org/T5819
Noteworthy changes in version 1.16.0 (2021-06-24)
-------------------------------------------------
* New context flag "cert-expire". [#5505]
* New data flags "io-buffer-size" and "sensitive". [#5478]
* Increase I/O buffer size from 512 to 4k under Windows.
* cpp,qt: Add support for trust signatures. [#5421]
* qt: Add support for flags in LDAP server options. [#5217]
* qt: Fix too high memory consumption due to QProcess. [#5475]
* qt: Do not set empty base DN as query of keyserver URL. [#5465]
* qt: Extend SignKeyJob to create signatures with expiration date.
[5506]
* python: New optional parameter filter_signatures for decrypt.
[#5292]
* Interface changes relative to the 1.15.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_ctx_flag EXTENDED: New flag 'cert-expire'.
cpp: SignKeyJob::setTrustSignature NEW.
cpp: TrustSignatureTrust NEW.
cpp: GpgSignKeyEditInteractor::setTrustSignatureTrust NEW.
cpp: GpgSignKeyEditInteractor::setTrustSignatureDepth NEW.
cpp: GpgSignKeyEditInteractor::setTrustSignatureScope NEW.
cpp: UserID::Signature::isTrustSignature NEW.
cpp: UserID::Signature::trustValue NEW.
cpp: UserID::Signature::trustDepth NEW.
cpp: UserID::Signature::trustScope NEW.
gpgme_key_sig_t EXTENDED: New field 'trust_depth'.
gpgme_key_sig_t EXTENDED: New field 'trust_value'.
gpgme_key_sig_t EXTENDED: New field 'trust_scope'.
GPGME_KEYSIGN_FORCE NEW.
qt: CryptoConfig::entry CHANGED: Added overload; deprecated old
[c=C36/A25/R0 cpp=C19/A13/R0 qt=C13/A6/R0]
Release-info: https://dev.gnupg.org/T5499
Noteworthy changes in version 1.15.1 (2021-01-08)
-------------------------------------------------
* Fix another bug in the secret key export. [#5046]
* Make listing of signatures work if only secret keys are listed. [#3580]
* Fix build problem on FreeBSD. [a6220adf30]
* qt: Avoid empty "rem@gnupg.org" signature notations. [#5142]
* python: Fix key_export functions. [#5149]
[c=C35/A24/R1 cpp=C18/A12/R1 qt=C12/A5/R1]
Release-info: https://dev.gnupg.org/T5225
Noteworthy changes in version 1.15.0 (2020-11-12)
-------------------------------------------------
* New function gpgme_op_setexpire to make changing the expiration
easier (requires GnuPG 2.1.22). [#4999]
* New function gpgme_op_revsig to revoke key signatures (requires
GnuPG 2.2.24). [#5094]
* Support exporting secret keys. [#5046]
* cpp: Support for set expire operations in the C++ bindings. [#5003]
* cpp: Support for revoking key signatures in the C++ bindings. [#5094]
* qt: Extended ChangeExpiryJob to support changing the expiry of
subkeys. [#4717]
* qt: Extended QuickJob to support revoking of key signatures. [#5094]
* qt: Added QDebug stream operator for GpgME::Error.
* Require a somewhat newer version of libgpg-error (1.36).
* Interface changes relative to the 1.14.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_op_setexpire_start NEW.
gpgme_op_setexpire NEW.
gpgme_op_revsig_start NEW.
gpgme_op_revsig NEW.
GPGME_REVSIG_LFSEP NEW.
cpp: Context::setExpire NEW.
cpp: Context::startSetExpire NEW.
cpp: EngineInfo::Version::operator<= NEW.
cpp: EngineInfo::Version::operator>= NEW.
cpp: EngineInfo::Version::operator!= NEW.
cpp: StatusConsumer NEW.
cpp: StatusConsumerAssuanTransaction NEW.
cpp: Context::cancelPendingOperationImmediately NEW.
cpp: Context::revokeSignature NEW.
cpp: Context::startRevokeSignature NEW.
cpp: UserID::Signature::operator< NEW.
qt: operator<<(QDebug debug, const GpgME::Error &err) NEW.
qt: QuickJob::startRevokeSignature NEW.
qt: QuickJob::result CHANGED: Made params 'auditLogAsHtml'
and 'auditLogError' optional.
[c=C35/A24/R0 cpp=C18/A12/R0 qt=C12/A5/R0]
Release-info: https://dev.gnupg.org/T5131
Noteworthy changes in version 1.14.0 (2020-07-16)
-------------------------------------------------
* New keylist mode to force the engine to return the keygrip. [#4820]
* New export mode to export as OpenSSH public key. [#4310]
* New context flag "extended-edit" to enable expert key edit. [#4734]
* Deprecate the anyway non working trustlist functions. [#4834]
* cpp: Add convenience API to obtain remarks. [#4734]
* cpp: The sign key edit-interactor now supports multiple signatures
from the same key. [#4734]
* qt: Extended signkeyjob to handle remarks and multiple signatures.
[#4734]
* qt: Added job API for gpg-card.
* qt: The logging category has been changed to gpg.qgpgme to be more
consistent with other qt logging categories.
* Interface changes relative to the 1.13.1 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_WITH_KEYGRIP NEW.
GPGME_EXPORT_MODE_SSH NEW.
gpgme_user_id_t EXTENDED: New field 'uidhash'.
cpp: UserID::remark NEW.
cpp: UserID::remarks NEW.
cpp: GpgSignKeyEditInteractor::setDupeOk NEW.
cpp: Context::exportPublicKeys EXTENDED: New param 'flags'.
cpp: Context::startPublicKeyExport EXTENDED: New param 'flags'.
cpp: Context::ExportMode NEW.
qt: SignKeyJob::setDupeOk NEW.
qt: SignKeyJob::setRemark NEW.
qt: GpgCardJob NEW.
qt: ExportJob::setExportFlags NEW.
[c=C34/A23/R0 cpp=C17/A11/R0 qt=C11/A4/R0]
Release-info: https://dev.gnupg.org/T4996
Noteworthy changes in version 1.13.1 (2019-06-13)
-------------------------------------------------
* cpp: gpgme_set_global_flag is now wrapped. [#4471]
* w32: Improved handling of unicode install paths. [#4453]
* w32: The gpgme_io_spawn error message is now only shown once. [#4453]
* Fixed a crash introduced in 1.13.0 when working with S/MIME. [#4556]
* w32: Fixed format string errors introduced in 1.13.0 that could
cause crashes. [#4440]
* w32: Fixed an error in the new diagnostic gpgsm support introduced
in 1.13.0 that caused crashes in low fd scenarios. [#4439]
* python: Fixed a DecryptionError Exception. [#4478]
* python: No longer raises BadSignatures from decrypt(verify=True).
[#4276]
* Interface changes relative to the 1.13.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cpp: setGlobalFlag NEW.
[c=C33/A22/R1 cpp=C16/A10/R0 qt=C10/A3/R4]
Release-info: https://dev.gnupg.org/T4551
Noteworthy changes in version 1.13.0 (2019-03-26)
-------------------------------------------------
* Support GPGME_AUDITLOG_DIAG for gpgsm. [#4426]
* New context flag "trust-model".
* Removed support for WindowsCE and Windows ME.
* Aligned the gpgrt-config code with our other libaries.
* Auto-check for all installed Python versions. [#3354]
* Fixed generating card key in the C++ bindings. [#4428]
* Fixed a segv due to bad parameters in genkey. [#4192]
* Fixed crash if the plaintext is ignored in a CMS verify.
* Fixed memleak on Windows. [T4238]
* Tweaked the Windows I/O code.
* Fixed random crashes on Windows due to closing an arbitrary
handle. [#4237]
* Fixed a segv on Windows. [#4369]
* Fixed test suite problems related to dtags. [#4298]
* Fixed bunch of python bugs. [#4242,commit 9de1c96ac3cf]
* Several fixes to the Common Lisp bindings.
* Fixed minor bugs in gpgme-json. [#4331,#4341,#4342,#4343]
* Require trace level 8 to dump all I/O data.
* The compiler must now support variadic macros.
* Interface changes relative to the 1.12.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gpgme_set_ctx_flag EXTENDED: New flag 'trust-model'.
cpp: Context::create NEW.
cpp: Key::isBad NEW.
cpp: Subkey::isBad NEW.
cpp: UserID::isBad NEW.
cpp: UserID::Signature::isBad NEW.
cpp: GenCardKeyInteractor::setAlgo NEW.
[c=C33/A22/R0 cpp=C15/A9/R0 qt=C10/A3/R3]
Release-info: https://dev.gnupg.org/T4376
Noteworthy changes in version 1.12.0 (2018-10-08)

8
README
View File

@ -1,7 +1,7 @@
GPGME - GnuPG Made Easy
---------------------------
Copyright 2001-2023 g10 Code GmbH
Copyright 2001-2018 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
@ -41,11 +41,11 @@ See the file INSTALL for generic installation instructions.
Check that you have unmodified sources. See below on how to do this.
Don't skip it - this is an important step!
To build GPGME, you need to install libgpg-error (>= 1.36) and
To build GPGME, you need to install libgpg-error (>= 1.24) and
Libassuan (>= 2.4.2).
For support of the OpenPGP and the CMS protocols, you should use at
least GnuPG version 2.2.41 or 2.4.3, available at:
For support of the OpenPGP and the CMS protocols, you should use the
latest version of GnuPG (>= 2.1.18) , available at:
https://gnupg.org/ftp/gcrypt/gnupg/.
For building the Git version of GPGME please see the file README.GIT

View File

@ -11,4 +11,4 @@ case "$myhost" in
esac
final_info="mkdir build && cd build && ../configure --enable-maintainer-mode && make"
final_info="./configure --enable-maintainer-mode && make"

View File

@ -1,6 +1,6 @@
#! /bin/sh
# autogen.sh
# Copyright (C) 2003, 2014, 2017, 2018, 2022 g10 Code GmbH
# Copyright (C) 2003, 2014, 2017, 2018 g10 Code GmbH
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
@ -15,7 +15,7 @@
# configure it for the respective package. It is maintained as part of
# GnuPG and source copied by other packages.
#
# Version: 2023-03-15
# Version: 2018-07-10
configure_ac="configure.ac"
@ -137,6 +137,8 @@ extraoptions=
# List of optional variables sourced from autogen.rc and ~/.gnupg-autogen.rc
w32_toolprefixes=
w32_extraoptions=
w32ce_toolprefixes=
w32ce_extraoptions=
w64_toolprefixes=
w64_extraoptions=
amd64_toolprefixes=
@ -144,6 +146,7 @@ amd64_toolprefixes=
# What follows are variables which are sourced but default to
# environment variables or lacking them hardcoded values.
#w32root=
#w32ce_root=
#w64root=
#amd64root=
@ -164,6 +167,11 @@ case "$1" in
myhost="w32"
shift
;;
--build-w32ce)
myhost="w32"
myhostsub="ce"
shift
;;
--build-w64)
myhost="w32"
myhostsub="64"
@ -195,7 +203,7 @@ if [ "$myhost" = "git-build" ]; then
die_p
make || fatal "error running make"
die_p
make check || fatal "error running make check"
make check || fatal "error running male check"
die_p
exit 0
fi
@ -233,12 +241,10 @@ if [ "$myhost" = "find-version" ]; then
if [ -z "$micro" ]; then
matchstr1="$package-$major.[0-9]*"
matchstr2="$package-$major-base"
matchstr3=""
vers="$major.$minor"
else
matchstr1="$package-$major.$minor.[0-9]*"
matchstr2="$package-$major.[0-9]*-base"
matchstr3="$package-$major-base"
matchstr2="$package-$major.$minor-base"
vers="$major.$minor.$micro"
fi
@ -246,22 +252,13 @@ if [ "$myhost" = "find-version" ]; then
if [ -e .git ]; then
ingit=yes
tmp=$(git describe --match "${matchstr1}" --long 2>/dev/null)
tmp=$(echo "$tmp" | sed s/^"$package"//)
if [ -n "$tmp" ]; then
tmp=$(echo "$tmp" | sed s/^"$package"// \
| awk -F- '$3!=0 && $3 !~ /^beta/ {print"-beta"$3}')
tmp=$(echo "$tmp" | sed s/^"$package"// \
| awk -F- '$3!=0 && $3 !~ /^beta/ {print"-beta"$3}')
else
# (due tof "-base" in the tag we need to take the 4th field)
tmp=$(git describe --match "${matchstr2}" --long 2>/dev/null)
if [ -n "$tmp" ]; then
tmp=$(echo "$tmp" | sed s/^"$package"// \
| awk -F- '$4!=0 && $4 !~ /^beta/ {print"-beta"$4}')
elif [ -n "${matchstr3}" ]; then
tmp=$(git describe --match "${matchstr3}" --long 2>/dev/null)
if [ -n "$tmp" ]; then
tmp=$(echo "$tmp" | sed s/^"$package"// \
| awk -F- '$4!=0 && $4 !~ /^beta/ {print"-beta"$4}')
fi
fi
tmp=$(git describe --match "${matchstr2}" --long 2>/dev/null \
| awk -F- '$4!=0{print"-beta"$4}')
fi
[ -n "$tmp" ] && beta=yes
rev=$(git rev-parse --short HEAD | tr -d '\n\r')
@ -297,6 +294,12 @@ fi
# ******************
if [ "$myhost" = "w32" ]; then
case $myhostsub in
ce)
w32root="$w32ce_root"
[ -z "$w32root" ] && w32root="$HOME/w32ce_root"
toolprefixes="$w32ce_toolprefixes arm-mingw32ce"
extraoptions="$extraoptions $w32ce_extraoptions"
;;
64)
w32root="$w64root"
[ -z "$w32root" ] && w32root="$HOME/w64root"

1612
build-aux/config.guess vendored

File diff suppressed because it is too large Load Diff

2909
build-aux/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
#
# This is a sed script to patch the generated libtool,
# which works well against both of libtool 2.4.2 and 2.4.7.
#
# You may use this work under the terms of a Creative Commons CC0 1.0
# License/Waiver.
#
# CC0 Public Domain Dedication
# https://creativecommons.org/publicdomain/zero/1.0/
#
# This sed script applys two hunks of the patch:
#
# Part1: after the comment "# bleh windows"
# Part2: after the comment "#extension on DOS 8.3..."
#
# Only when those two parts are patched correctly, it exits with 0 or
# else, it exits with 1
#
# Find the part 1, by the comment
/^[ \t]*# bleh windows$/b part1_start
# Not found the part1, raise an error
$ q1
b
:part1_start
n
# The first line in the part 1 must be the begining of the case statement.
/^[ \t]*case \$host in$/! q1
n
# Insert the entry for x86_64-*mingw32*, for modified versuffix.
i\
x86_64-*mingw32*)
i\
func_arith $current - $age
i\
major=$func_arith_result
i\
versuffix="6-$major"
i\
;;
:part1_0
# Find the end of the case statement
/^[ \t]*esac$/b find_part2
# Not found the end of the case statement, raise an error
$ q1
n
b part1_0
:find_part2
/^[ \t]*# extension on DOS 8.3 file.*systems.$/b part2_process
# Not found the part2, raise an error
$ q1
n
b find_part2
:part2_process
$ q1
s/^[ \t]*\(versuffix=\)\(.*\)\(-$major\)\(.*\)$/\t case \$host in\n\t x86_64-*mingw32*)\n\t \1\26\3\4\n\t ;;\n\t *)\n\t \1\2\3\4\n\t ;;\n\t esac/
t part2_done
n
b part2_process
:part2_done
$ q0
n
b part2_done

View File

@ -482,7 +482,7 @@
% \def\foo{\parsearg\Xfoo}
% \def\Xfoo#1{...}
%
% Actually, I use \csname\string\foo\endcsname, i.e. \\foo, as it is my
% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my
% favourite TeX trick. --kasal, 16nov03
\def\parseargdef#1{%

View File

@ -1,6 +1,6 @@
# configure.ac for GPGME
# Copyright (C) 2000 Werner Koch (dd9jn)
# Copyright (C) 2001-2021 g10 Code GmbH
# Copyright (C) 2001-2018 g10 Code GmbH
#
# This file is part of GPGME.
#
@ -19,20 +19,18 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# (Process this file with autoconf to produce a configure script.)
AC_PREREQ([2.69])
AC_PREREQ(2.59)
min_automake_version="1.14"
# To build a release you need to create a tag with the version number
# "gpgme-n.m.k" and run "./autogen.sh --force". Please bump the
# version number immediately after the release and do another commit
# and push so that the git magic is able to work. If you start a new
# series by bumping the minor (m) remember to also create a tag named
# "gpgme-n.m-base" as the start point for beta numbering. See below
# (git tag -s gpgme-n.m.k) and run "./autogen.sh --force". Please
# bump the version number immediately after the release and do another
# commit and push so that the git magic is able to work. See below
# for the LT versions.
m4_define([mym4_package],[gpgme])
m4_define([mym4_major], [1])
m4_define([mym4_minor], [24])
m4_define([mym4_micro], [0])
m4_define([mym4_minor], [12])
m4_define([mym4_micro], [1])
# Below is m4 magic to extract and compute the git revision number,
# the decimalized short revision number, a beta version string and a
@ -45,7 +43,7 @@ m4_define([mym4_version], m4_argn(4, mym4_verslist))
m4_define([mym4_revision], m4_argn(7, mym4_verslist))
m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist))
m4_esyscmd([echo ]mym4_version[>VERSION])
AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
# LT Version numbers, remember to change them just *before* a release.
# (Code changed: REVISION++)
@ -53,20 +51,20 @@ AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
# (Interfaces added: AGE++)
# (Interfaces removed: AGE=0)
#
LIBGPGME_LT_CURRENT=43
LIBGPGME_LT_AGE=32
LIBGPGME_LT_REVISION=1
LIBGPGME_LT_CURRENT=32
LIBGPGME_LT_AGE=21
LIBGPGME_LT_REVISION=0
# If there is an ABI break in gpgmepp or qgpgme also bump the
# version in IMPORTED_LOCATION in the GpgmeppConfig-w32.cmake.in.in
LIBGPGMEPP_LT_CURRENT=26
LIBGPGMEPP_LT_AGE=20
LIBGPGMEPP_LT_REVISION=1
LIBGPGMEPP_LT_CURRENT=14
LIBGPGMEPP_LT_AGE=8
LIBGPGMEPP_LT_REVISION=0
LIBQGPGME_LT_CURRENT=20
LIBQGPGME_LT_AGE=5
LIBQGPGME_LT_REVISION=1
LIBQGPGME_LT_CURRENT=10
LIBQGPGME_LT_AGE=3
LIBQGPGME_LT_REVISION=2
################################################
AC_SUBST(LIBGPGME_LT_CURRENT)
@ -85,7 +83,7 @@ AC_SUBST(LIBQGPGME_LT_REVISION)
GPGME_CONFIG_API_VERSION=1
##############################################
NEED_GPG_ERROR_VERSION=1.47
NEED_GPG_ERROR_VERSION=1.24
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.4.2
@ -96,8 +94,8 @@ VERSION_MICRO=mym4_micro
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/gpgme.h.in])
AC_CONFIG_HEADERS([conf/config.h])
AC_CONFIG_SRCDIR(src/gpgme.h.in)
AC_CONFIG_HEADER(conf/config.h)
AM_INIT_AUTOMAKE([serial-tests dist-bzip2 no-dist-gzip])
AM_MAINTAINER_MODE
AC_CANONICAL_HOST
@ -105,42 +103,7 @@ AM_SILENT_RULES
AC_ARG_VAR(SYSROOT,[locate config scripts also below that directory])
# Enable GNU extensions on systems that have them.
AC_USE_SYSTEM_EXTENSIONS
# Taken from mpfr-4.0.1, then modified for LDADD_FOR_TESTS_KLUDGE
dnl Under Linux, make sure that the old dtags are used if LD_LIBRARY_PATH
dnl is defined. The issue is that with the new dtags, LD_LIBRARY_PATH has
dnl the precedence over the run path, so that if a compatible MPFR library
dnl is installed in some directory from $LD_LIBRARY_PATH, then the tested
dnl MPFR library will be this library instead of the MPFR library from the
dnl build tree. Other OS with the same issue might be added later.
dnl
dnl References:
dnl https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
dnl http://lists.gnu.org/archive/html/libtool/2017-05/msg00000.html
dnl
dnl We need to check whether --disable-new-dtags is supported as alternate
dnl linkers may be used (e.g., with tcc: CC=tcc LD=tcc).
dnl
case $host in
*-*-linux*)
if test -n "$LD_LIBRARY_PATH"; then
saved_LDFLAGS="$LDFLAGS"
LDADD_FOR_TESTS_KLUDGE="-Wl,--disable-new-dtags"
LDFLAGS="$LDFLAGS $LDADD_FOR_TESTS_KLUDGE"
AC_MSG_CHECKING(whether --disable-new-dtags is supported by the linker)
AC_LINK_IFELSE([AC_LANG_SOURCE([[
int main (void) { return 0; }
]])],
[AC_MSG_RESULT(yes (use it since LD_LIBRARY_PATH is set))],
[AC_MSG_RESULT(no)
LDADD_FOR_TESTS_KLUDGE=""
])
LDFLAGS="$saved_LDFLAGS"
fi
;;
esac
AC_SUBST([LDADD_FOR_TESTS_KLUDGE])
AC_GNU_SOURCE
AH_VERBATIM([_REENTRANT],
[/* To allow the use of GPGME in multithreaded programs we have to use
@ -198,7 +161,7 @@ case "${host}" in
have_ld_version_script=yes
;;
*-apple-darwin*)
AC_DEFINE(_DARWIN_C_SOURCE, 1,
AC_DEFINE(_DARWIN_C_SOURCE, 900000L,
Expose all libc features (__DARWIN_C_FULL).)
AC_DEFINE(_XOPEN_SOURCE, 500, Activate POSIX interface on MacOS X)
;;
@ -206,44 +169,6 @@ esac
AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
#
# Specify how we support our local modification of libtool for Windows
# 64-bit. Options are:
#
# (1) apply: when appying patch fails, it results failure of entire build
# (2) never: never apply the patch (no try)
# (3) try: use patched if it goes well, use original if fails
#
AC_ARG_WITH([libtool-modification],
AS_HELP_STRING([--with-libtool-modification=apply|never|try],
[how to handle libtool modification (default=never)]),
build_libtool_modification=$withval,
build_libtool_modification=never)
#
# Apply a patch (locally maintained one of ours) to libtool
#
case $host in
x86_64-*mingw32*)
AC_CONFIG_COMMANDS([libtool-patch],[[
if test "$build_selection" = never; then
echo "patch not applied"
elif (mv -f libtool libtool.orig; \
sed -f $srcdir/build-aux/libtool-patch.sed libtool.orig >libtool); then
echo "applied successfully"
elif test "$build_selection" = try; then
mv -f libtool.orig libtool
echo "patch failed, thus, using original"
else
echo "patch failed"
as_fn_exit 1
fi
]],[build_selection=$build_libtool_modification])
;;
*)
;;
esac
GPG_DEFAULT=no
GPGSM_DEFAULT=no
GPGCONF_DEFAULT=no
@ -256,8 +181,8 @@ have_w64_system=no
have_macos_system=no
build_w32_glib=no
build_w32_qt=no
available_languages="cl cpp python qt qt5 qt6"
default_languages="cl cpp python qt5 qt6"
available_languages="cl cpp python qt"
default_languages="cl cpp python qt"
case "${host}" in
x86_64-*mingw32*)
have_w64_system=yes
@ -281,7 +206,7 @@ case "${host}" in
AM_PATH_GLIB_2_0
AC_ARG_ENABLE(w32-glib,
AS_HELP_STRING([--enable-w32-glib],[build GPGME Glib for W32]),
AC_HELP_STRING([--enable-w32-glib], [build GPGME Glib for W32]),
build_w32_glib=$enableval)
;;
*)
@ -329,7 +254,7 @@ AM_CONDITIONAL(BUILD_W32_GLIB, test "$build_w32_glib" = yes)
AC_ARG_ENABLE([fixed-path],
AS_HELP_STRING([--enable-fixed-path=PATH],
AC_HELP_STRING([--enable-fixed-path=PATH],
[locate binaries only via this PATH]),
[fixed_search_path="$enableval"],
[fixed_search_path=""])
@ -338,44 +263,12 @@ if test x$fixed_search_path != x ; then
[Locate binaries only via this PATH])
fi
# Option --enable-reduce-relocations
#
# Allow building the Qt 6 bindings explicitly with -fPIC if the automatic
# detection fails. Note: We assume that this flag is always available (unless
# we built for Windows).
AC_ARG_ENABLE([reduce-relocations],
AS_HELP_STRING([--enable-reduce-relocations],
[build Qt 6 bindings with -fPIC (default is
auto)]),
[use_reduce_relocations="$enableval"],
[use_reduce_relocations=""])
# Option --enable-no-direct-extern-access
#
# Some distributions build Qt 6 with -mno-direct-extern-access. Libraries and
# applications using Qt then must also be build with this flag. As workaround
# for a bug in Qt's pkgconfig files which don't have this flag we allow
# building with this flag explicitly.
AC_LANG_PUSH(C++)
AX_CHECK_COMPILE_FLAG([-mno-direct-extern-access],
[have_no_direct_extern_access="yes"],
[have_no_direct_extern_access="no"],
[-Werror])
AC_LANG_POP()
AC_ARG_ENABLE([no-direct-extern-access],
AS_HELP_STRING([--enable-no-direct-extern-access],
[build Qt 6 bindings with
-mno-direct-extern-access (default is auto)]),
[use_no_direct_extern_access="$enableval"],
[use_no_direct_extern_access=""])
# Note: You need to declare all possible languages also in
# lang/Makefile.am's DIST_SUBDIRS.
AC_ARG_ENABLE([languages],
AS_HELP_STRING([--enable-languages=languages],
[enable only specific language bindings:
cl cpp python qt5 qt6]),
AC_HELP_STRING([--enable-languages=languages],
[enable only specific language bindings]),
[enabled_languages=`echo $enableval | \
tr ',:' ' ' | tr '[A-Z]' '[a-z]' | \
sed 's/c++/cpp/'`],
@ -401,182 +294,69 @@ for language in $enabled_languages; do
fi
done
# Check whether qt5 and/or qt6 are enabled
want_qt5="no"
LIST_MEMBER("qt5", $enabled_languages)
if test "$found" = "1"; then
if test "$explicit_languages" = "1"; then
want_qt5="yes"
else
want_qt5="maybe"
fi
# Remove qt5; further down qt will be added
enabled_languages=$(echo $enabled_languages | sed 's/qt5//')
fi
want_qt6="no"
LIST_MEMBER("qt6", $enabled_languages)
if test "$found" = "1"; then
if test "$explicit_languages" = "1"; then
want_qt6="yes"
else
want_qt6="maybe"
fi
# Remove qt6; further down qt will be added
enabled_languages=$(echo $enabled_languages | sed 's/qt6//')
fi
# Check whether qt is enabled; if yes then it has been enabled explicitly
want_qt="no"
LIST_MEMBER("qt", $enabled_languages)
if test "$found" = "1"; then
# Ignore qt if specified together with qt5 or qt6
if test "$want_qt5" = "no" -a "$want_qt6" = "no"; then
want_qt="yes"
fi
# Remove qt
enabled_languages=$(echo $enabled_languages | sed 's/qt//')
AC_MSG_WARN([[
***
*** Language binding "qt" is deprecated and will be removed in a future version.
*** Use "qt5" and/or "qt6" instead.
***]])
fi
# Ensure that pkg-config is available for all calls of FIND_QT5/FIND_QT6
PKG_PROG_PKG_CONFIG
# Check for Qt 5 (if qt5 or qt is enabled)
if test "$want_qt" = "yes"; then
want_qt5="maybe"
fi
if test "$want_qt5" != "no"; then
FIND_QT5
if test "$have_qt5_libs" = "yes"; then
want_qt5="yes"
elif test "$want_qt5" = "yes"; then
AC_MSG_ERROR([[
***
*** Qt5 (Qt5Core) is required for the Qt 5 binding.
***]])
else
want_qt5="no"
fi
fi
# Check for Qt 6 (if qt6 is enabled or if qt is enabled and Qt 5 wasn't found)
if test "$want_qt" = "yes" -a "$have_qt5_libs" != "yes"; then
want_qt6="maybe"
fi
if test "$want_qt6" != "no"; then
FIND_QT6
if test "$have_qt6_libs" = "yes"; then
want_qt6="yes";
elif test "$want_qt6" = "yes"; then
AC_MSG_ERROR([[
***
*** Qt6 (Qt6Core) is required for the Qt 6 binding.
***]])
else
want_qt6="no"
fi
fi
# Check if any Qt was found (if qt is enabled)
if test "$want_qt" = "yes" -a "$have_qt5_libs" != "yes" -a "$have_qt6_libs" != "yes"; then
AC_MSG_ERROR([[
***
*** Qt5 (Qt5Core) or Qt6 (Qt6Core) is required for the Qt bindings.
***]])
fi
# Check that cpp is enabled if qt5 or qt6 is enabled and was found
if test "$want_qt5" = "yes" -o "$want_qt6" = "yes"; then
LIST_MEMBER("cpp", $enabled_languages)
if test "$found" = "0"; then
AC_MSG_ERROR([[
***
*** The Qt bindings depend on the C++ binding.
***]])
fi
fi
# Enable C++ 17 if qt6 is requested
if test "$want_qt6" = "yes"; then
AX_CXX_COMPILE_STDCXX(17, noext, optional)
if test "$HAVE_CXX17" != "1"; then
if test "$explicit_languages" = "1"; then
AC_MSG_ERROR([[
***
*** A compiler with c++17 support is required for the Qt 6 binding.
***]])
else
want_qt6="no"
AC_MSG_WARN([[
***
*** No c++17 support detected. Qt 6 binding will be disabled.
***]])
fi
fi
fi
# Enable C++ 11 if cpp is requested (unless C++ 17 was already enabled)
# Enable C++ 11 if cpp language is requested
LIST_MEMBER("cpp", $enabled_languages)
if test "$found" = "1" -a "$HAVE_CXX17" != "1"; then
if test "$found" = "1"; then
AX_CXX_COMPILE_STDCXX(11, noext, optional)
if test "$HAVE_CXX11" != "1"; then
if test "$explicit_languages" = "1"; then
AC_MSG_ERROR([[
***
*** A compiler with c++11 support is required for the C++ binding.
*** A compiler with c++11 support is required for the c++ binding.
***]])
else
enabled_languages=$(echo $enabled_languages | sed 's/cpp//')
want_qt5="no"
enabled_languages=$(echo $enabled_languages | sed 's/qt//')
AC_MSG_WARN([[
***
*** No c++11 support detected. C++ and Qt 5 bindings will be disabled.
*** No c++11 support detected. C++ and Qt bindings will be disabled.
***]])
fi
fi
fi
# Now append qt to the list of language bindings (to enable the subdir in lang)
if test "$want_qt5" = "yes" -o "$want_qt6" = "yes"; then
enabled_languages=$(echo $enabled_languages qt)
fi
# Check whether compiler supports visibility attribute (if cpp language is enabled)
LIST_MEMBER("cpp", $enabled_languages)
# Check that if qt is enabled cpp also is enabled
LIST_MEMBER("qt", $enabled_languages)
if test "$found" = "1"; then
AX_GCC_FUNC_ATTRIBUTE(visibility)
if test "$ax_cv_have_func_attribute_visibility" = "yes"; then
GPGME_CPP_CFLAGS="$GPGME_CPP_CFLAGS -fvisibility=hidden"
if test "$want_qt5" = "yes"; then
GPGME_QT5_CFLAGS="$GPGME_QT5_CFLAGS -fvisibility=hidden"
# We need to ensure that in the language order qt comes after cpp
# so we remove qt first and explicitly add it as last list member.
enabled_languages=$(echo $enabled_languages | sed 's/qt//')
LIST_MEMBER("cpp", $enabled_languages)
if test "$found" = "0"; then
AC_MSG_ERROR([[
***
*** Qt language binding depends on cpp binding.
***]])
fi
FIND_QT
if test "$have_qt5_libs" != "yes"; then
if test "$explicit_languages" = "1"; then
AC_MSG_ERROR([[
***
*** Qt5 (Qt5Core) is required for Qt binding.
***]])
else
AC_MSG_WARN([[
***
*** Qt5 (Qt5Core) not found Qt Binding will be disabled.
***]])
fi
if test "$want_qt6" = "yes"; then
GPGME_QT6_CFLAGS="$GPGME_QT6_CFLAGS -fvisibility=hidden"
else
enabled_languages=`echo $enabled_languages qt`
AC_CHECK_PROGS([DOXYGEN], [doxygen])
if test -z "$DOXYGEN";
# This is not highlighted because it's not really important.
then AC_MSG_WARN([Doxygen not found - Qt binding doc will not be built.])
fi
AC_CHECK_PROGS([GRAPHVIZ], [dot])
if test -z "$GRAPHVIZ";
then AC_MSG_WARN([Graphviz not found - Qt binding doc will not have diagrams.])
fi
fi
fi
AC_SUBST(GPGME_CPP_CFLAGS)
AM_CONDITIONAL(WANT_QT5, test "$want_qt5" = yes)
AM_CONDITIONAL(WANT_QT6, test "$want_qt6" = yes)
# Check for tools for building the Qt binding docs
if test "$want_qt5" = "yes" -o "$want_qt6" = "yes"; then
AC_CHECK_PROGS([DOXYGEN], [doxygen])
if test -z "$DOXYGEN"; then
# This is not highlighted because it's not really important.
AC_MSG_WARN([Doxygen not found - Qt binding doc will not be built.])
fi
AC_CHECK_PROGS([GRAPHVIZ], [dot])
if test -z "$GRAPHVIZ"; then
AC_MSG_WARN([Graphviz not found - Qt binding doc will not have diagrams.])
fi
fi
AM_CONDITIONAL([HAVE_DOXYGEN],
[test -n "$DOXYGEN"])
if test -n "$GRAPHVIZ"; then
@ -608,12 +388,11 @@ if test "$found_py" = "1"; then
if test "$found_py" = "1" -o "$found_py3" = "1"; then
# Reset everything, so that we can look for another Python.
m4_foreach([mym4pythonver],
[[2.7],[3.6],[3.8],[3.9],[3.10],[3.11],[3.12],[all]],
[[2.7],[3.4],[3.5],[3.6],[3.7],[3.8],[all]],
[unset PYTHON
unset PYTHON_VERSION
unset PYTHON_CPPFLAGS
unset PYTHON_LDFLAGS
unset PYTHON_LIBS
unset PYTHON_SITE_PKG
unset PYTHON_EXTRA_LIBS
unset PYTHON_EXTRA_LDFLAGS
@ -624,7 +403,7 @@ if test "$found_py" = "1"; then
unset am_cv_python_pythondir
unset am_cv_python_pyexecdir
AM_PATH_PYTHON(mym4pythonver, [
AX_PYTHON_DEVEL([], [true])
AX_PYTHON_DEVEL
if test "$PYTHON_VERSION"; then
PYTHONS="$(echo $PYTHONS $PYTHON)"
PYTHON_VERSIONS="$(echo $PYTHON_VERSIONS $PYTHON_VERSION)"
@ -678,7 +457,7 @@ AC_SUBST(BUILD_VERSION)
AC_SUBST(BUILD_FILEVERSION)
AC_ARG_ENABLE([build-timestamp],
AS_HELP_STRING([--enable-build-timestamp],
AC_HELP_STRING([--enable-build-timestamp],
[set an explicit build timestamp for reproducibility.
(default is the current time in ISO-8601 format)]),
[if test "$enableval" = "yes"; then
@ -697,37 +476,36 @@ AC_DEFINE_UNQUOTED(BUILD_TIMESTAMP, "$BUILD_TIMESTAMP",
#
run_gpgconf_test="yes"
AC_ARG_ENABLE(gpgconf-test,
AS_HELP_STRING([--disable-gpgconf-test],[disable GPGCONF regression test]),
AC_HELP_STRING([--disable-gpgconf-test], [disable GPGCONF regression test]),
run_gpgconf_test=$enableval)
AM_CONDITIONAL(RUN_GPGCONF_TESTS, test "$run_gpgconf_test" = "yes")
run_gpg_test="yes"
AC_ARG_ENABLE(gpg-test,
AS_HELP_STRING([--disable-gpg-test],[disable GPG regression test]),
AC_HELP_STRING([--disable-gpg-test], [disable GPG regression test]),
run_gpg_test=$enableval)
AM_CONDITIONAL(RUN_GPG_TESTS, test "$run_gpg_test" = "yes")
run_gpgsm_test="yes"
AC_ARG_ENABLE(gpgsm-test,
AS_HELP_STRING([--disable-gpgsm-test],[disable GPGSM regression test]),
AC_HELP_STRING([--disable-gpgsm-test], [disable GPGSM regression test]),
run_gpgsm_test=$enableval)
AM_CONDITIONAL(RUN_GPGSM_TESTS, test "$run_gpgsm_test" = "yes")
run_g13_test="yes"
AC_ARG_ENABLE(g13-test,
AS_HELP_STRING([--disable-g13-test],[disable G13 regression test]),
AC_HELP_STRING([--disable-g13-test], [disable G13 regression test]),
run_g13_test=$enableval)
AM_CONDITIONAL(RUN_G13_TESTS, test "$run_g13_test" = "yes")
# Checks for header files.
AC_CHECK_HEADERS_ONCE([locale.h sys/select.h sys/uio.h argp.h stdint.h
unistd.h poll.h sys/time.h sys/types.h sys/stat.h])
unistd.h sys/time.h sys/types.h sys/stat.h])
# Type checks.
AC_C_INLINE
AC_C_FLEXIBLE_ARRAY_MEMBER
AC_CHECK_SIZEOF(unsigned int)
AC_SYS_LARGEFILE
AC_TYPE_OFF_T
@ -786,30 +564,25 @@ AM_SUBST_NOTMAKE(API__SSIZE_T)
# Checks for compiler features.
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
CFLAGS="$CFLAGS -Wno-format-y2k"
# If -Wno-missing-field-initializers is supported we can expect a
# a larger set of warning options.
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wno-missing-field-initializers"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_wopt=yes,_gcc_wopt=no)
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -Wno-missing-field-initializers"
CFLAGS="$CFLAGS -Wno-sign-compare"
CFLAGS="$CFLAGS -Wno-format-zero-length"
CFLAGS="$CFLAGS -Wno-format-truncation"
CFLAGS="$CFLAGS -Wno-sizeof-pointer-div"
fi
if test "$USE_MAINTAINER_MODE" = "yes"; then
CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security"
# If -Wno-missing-field-initializers is supported we can enable a
# a bunch of really useful warnings.
AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wno-missing-field-initializers"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_wopt=yes,_gcc_wopt=no)
AC_MSG_RESULT($_gcc_wopt)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_wopt" = xyes ; then
CFLAGS="$CFLAGS -W -Wextra -Wbad-function-cast"
CFLAGS="$CFLAGS -Wwrite-strings"
CFLAGS="$CFLAGS -Wdeclaration-after-statement"
CFLAGS="$CFLAGS -Wno-missing-field-initializers"
CFLAGS="$CFLAGS -Wno-sign-compare"
CFLAGS="$CFLAGS -Wno-format-zero-length"
fi
CFLAGS="$CFLAGS -Wformat -Wformat-security"
CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wno-shadow"
AC_MSG_CHECKING([if gcc supports -Wpointer-arith])
@ -890,9 +663,6 @@ AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_GPGME,
[The default error source for GPGME.])
AM_CONDITIONAL(USE_GPGRT_CONFIG, [test -n "$GPGRT_CONFIG" \
-a "$ac_cv_path_GPG_ERROR_CONFIG" = no])
# And for libassuan.
have_libassuan=no
AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_API:$NEED_LIBASSUAN_VERSION",
@ -908,7 +678,7 @@ fi
#
# Check for getgid etc
AC_CHECK_FUNCS(getgid getegid closefrom nanosleep)
AC_CHECK_FUNCS(getgid getegid closefrom)
# Replacement functions.
@ -938,7 +708,7 @@ AC_CHECK_MEMBER(struct cmsghdr.cmsg_len,
use_descriptor_passing=yes
AC_ARG_ENABLE(fd-passing,
AS_HELP_STRING([--disable-fd-passing],[do not use FD passing]),
AC_HELP_STRING([--disable-fd-passing], [do not use FD passing]),
use_descriptor_passing=$enableval)
if test "$supports_descriptor_passing" != "yes"; then
@ -970,7 +740,7 @@ AM_CONDITIONAL(HAVE_UISERVER, test "$uiserver" != "no")
# before an exec. This option allows to switch this optimization off.
use_linux_getdents=yes
AC_ARG_ENABLE(linux-getdents,
AS_HELP_STRING([--disable-linux-getdents],
AC_HELP_STRING([--disable-linux-getdents],
[do not use SYS_getdents on Linux]),
use_linux_getdents=$enableval)
if test "$use_linux_getdents" = "yes"; then
@ -1008,56 +778,19 @@ AH_BOTTOM([
# define GPGME_GCC_A_PURE
#endif
/* Under Windows we use the gettext code from gpgrt. */
#define GPG_ERR_ENABLE_GETTEXT_MACROS 1
/* Under WindowsCE we need gpg-error's strerror macro. */
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define CRIGHTBLURB "Copyright (C) 2000 Werner Koch\n" \
"Copyright (C) 2001--2021 g10 Code GmbH\n"
"Copyright (C) 2001--2018 g10 Code GmbH\n"
])
# Substitution used for gpgme-config and gpgme.pc
# Substitution used for gpgme-config
GPGME_CONFIG_LIBS="-lgpgme"
GPGME_CONFIG_CFLAGS=""
GPGME_CONFIG_HOST="$host"
GPGME_CONFIG_AVAIL_LANG="$enabled_languages"
case "$includedir" in
/usr/include|/include) ;;
'${prefix}/include')
if test "$prefix" != / -a "$prefix" != /usr; then
if test -z "$GPGME_CONFIG_CFLAGS"; then
GPGME_CONFIG_CFLAGS="-I\${includedir}"
else
GPGME_CONFIG_CFLAGS="-I\${includedir} $GPGME_CONFIG_CFLAGS"
fi
fi
;;
*)
if test -z "$GPGME_CONFIG_CFLAGS"; then
GPGME_CONFIG_CFLAGS="-I\${includedir}"
else
GPGME_CONFIG_CFLAGS="-I\${includedir} $GPGME_CONFIG_CFLAGS"
fi
;;
esac
case "$libdir" in
/usr/lib|/usr/lib64|/lib|/lib64) ;;
'${exec_prefix}/lib'|'${exec_prefix}/lib64')
if test "$exec_prefix" = "NONE"; then
if test "$prefix" != / -a "$prefix" != /usr; then
GPGME_CONFIG_LIBS="-L\${libdir} $GPGME_CONFIG_LIBS"
fi
elif test "$exec_prefix" != / -a "$exec_prefix" != /usr; then
GPGME_CONFIG_LIBS="-L\${libdir} $GPGME_CONFIG_LIBS"
fi
;;
*) GPGME_CONFIG_LIBS="-L\${libdir} $GPGME_CONFIG_LIBS" ;;
esac
AC_SUBST(GPGME_CONFIG_API_VERSION)
AC_SUBST(GPGME_CONFIG_LIBS)
AC_SUBST(GPGME_CONFIG_CFLAGS)
@ -1136,16 +869,9 @@ AC_CONFIG_FILES(lang/cpp/src/GpgmeppConfig.cmake.in)
AC_CONFIG_FILES(lang/cpp/src/GpgmeppConfigVersion.cmake)
AC_CONFIG_FILES(lang/cpp/src/gpgmepp_version.h)
AC_CONFIG_FILES(lang/qt/Makefile lang/qt/src/Makefile)
if test "$want_qt5" = "yes"; then
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfig-w32.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfig.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfigVersion.cmake)
fi
if test "$want_qt6" = "yes"; then
AC_CONFIG_FILES(lang/qt/src/QGpgmeQt6Config-w32.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeQt6Config.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeQt6ConfigVersion.cmake)
fi
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfig-w32.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfig.cmake.in)
AC_CONFIG_FILES(lang/qt/src/QGpgmeConfigVersion.cmake)
AC_CONFIG_FILES(lang/qt/tests/Makefile)
AC_CONFIG_FILES(lang/qt/src/qgpgme_version.h)
AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpgme.asd])
@ -1156,21 +882,10 @@ AC_CONFIG_FILES([lang/js/Makefile lang/js/src/Makefile
AC_CONFIG_FILES(lang/qt/doc/Makefile)
AC_CONFIG_FILES([lang/python/Makefile
lang/python/version.py
lang/python/tests/Makefile
lang/python/src/Makefile
lang/python/examples/Makefile
lang/python/doc/Makefile])
lang/python/tests/Makefile])
AC_CONFIG_FILES([lang/python/setup.py], [chmod a+x lang/python/setup.py])
AC_OUTPUT
if test "$want_qt5" = "yes" -a "$want_qt6" = "yes"; then
enabled_languages_v=$(echo ${enabled_languages_v:-$enabled_languages} | sed "s/qt/qt (Qt 5, Qt 6)/")
elif test "$want_qt5" = "yes"; then
enabled_languages_v=$(echo ${enabled_languages_v:-$enabled_languages} | sed "s/qt/qt (Qt 5)/")
elif test "$want_qt6" = "yes"; then
enabled_languages_v=$(echo ${enabled_languages_v:-$enabled_languages} | sed "s/qt/qt (Qt 6)/")
fi
echo "
GPGME v${VERSION} has been configured as follows:

File diff suppressed because it is too large Load Diff

View File

@ -498,7 +498,7 @@
% \def\foo{\parsearg\Xfoo}
% \def\Xfoo#1{...}
%
% Actually, I use \csname\string\foo\endcsname, i.e. \\foo, as it is my
% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my
% favourite TeX trick. --kasal, 16nov03
\def\parseargdef#1{%

View File

@ -18,12 +18,6 @@
# License along with this program; if not, see <https://gnu.org/licenses/>.
# SPDX-License-Identifier: LGPL-2.1-or-later
if RUN_GPG_TESTS
tests = tests
else
tests =
endif
SUBDIRS = src ${tests}
SUBDIRS = src tests
EXTRA_DIST = README

View File

@ -97,3 +97,7 @@ unset(_IMPORT_CHECK_TARGETS)
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
get_filename_component(QGpgme_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# Pull in QGpgme for compatibility with KF5 variant.
find_package(QGpgme CONFIG)

View File

@ -93,3 +93,7 @@ unset(_IMPORT_CHECK_TARGETS)
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
get_filename_component(QGpgme_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# Pull in QGpgme for compatibility with KF5 variant.
find_package(QGpgme CONFIG)

View File

@ -33,13 +33,9 @@ main_sources = \
engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \
gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \
gpgadduserideditinteractor.cpp gpggencardkeyinteractor.cpp \
gpgaddexistingsubkeyeditinteractor.cpp \
gpgrevokekeyeditinteractor.cpp \
defaultassuantransaction.cpp \
scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \
statusconsumerassuantransaction.cpp \
vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp \
util.cpp
vfsmountresult.cpp configuration.cpp tofuinfo.cpp swdbresult.cpp
gpgmepp_headers = \
configuration.h context.h data.h decryptionresult.h \
@ -49,11 +45,8 @@ gpgmepp_headers = \
gpgmefw.h gpgsetexpirytimeeditinteractor.h \
gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \
gpggencardkeyinteractor.h \
gpgaddexistingsubkeyeditinteractor.h \
gpgrevokekeyeditinteractor.h \
importresult.h keygenerationresult.h key.h keylistresult.h \
notation.h result.h scdgetinfoassuantransaction.h signingresult.h \
statusconsumerassuantransaction.h \
trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \
tofuinfo.h swdbresult.h
@ -62,8 +55,7 @@ private_gpgmepp_headers = \
interface_headers= \
interfaces/assuantransaction.h interfaces/dataprovider.h \
interfaces/passphraseprovider.h interfaces/progressprovider.h \
interfaces/statusconsumer.h
interfaces/passphraseprovider.h interfaces/progressprovider.h
gpgmeppincludedir = $(includedir)/gpgme++
gpgmeppinclude_HEADERS = $(gpgmepp_headers)
@ -73,8 +65,7 @@ nodist_gpgmeppinclude_HEADERS = gpgmepp_version.h
libgpgmepp_la_SOURCES = $(main_sources) $(gpgmepp_headers) context_vanilla.cpp \
$(interface_headers) $(private_gpgmepp_headers)
AM_CPPFLAGS = -I$(top_builddir)/src \
@GPGME_CPP_CFLAGS@ @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
-DBUILDING_GPGMEPP -Wsuggest-override \
-Wzero-as-null-pointer-constant
@ -88,14 +79,6 @@ else
libsuffix=.so
endif
copied_headers = $(gpgmepp_headers:%=gpgme++/%) $(interface_headers:%=gpgme++/%)
$(copied_headers): Makefile.am
mkdir -p $(builddir)/gpgme++/interfaces
echo -n "#include \"$(abs_srcdir)" > "$@"
echo -n "$@" | sed "s/gpgme++//" >> "$@"
echo "\"" >> "$@"
if HAVE_W32_SYSTEM
GpgmeppConfig.cmake: GpgmeppConfig-w32.cmake.in
sed -e 's|[@]resolved_bindir@|$(bindir)|g' < "$<" | \
@ -123,8 +106,5 @@ install-data-local: install-cmake-files
uninstall-local: uninstall-cmake-files
BUILT_SOURCES = $(copied_headers)
CLEANFILES = GpgmeppConfig.cmake GpgmeppConfigVersion.cmake \
gpgmepp_version.h GpgmeppConfig.cmake.in \
$(copied_headers)
gpgmepp_version.h GpgmeppConfig.cmake.in

View File

@ -257,6 +257,158 @@ Type Option::alternateType() const
return isNull() ? NoType : static_cast<Type>(opt->alt_type) ;
}
#if 0
static Option::Variant argument_to_variant(gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg)
{
assert(arg);
switch (type) {
case GPGME_CONF_NONE:
if (list) {
// return the count (number of times set):
return arg->value.count;
} else {
return none;
}
case GPGME_CONF_INT32:
if (list) {
std::vector<int> result;
for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
result.push_back(a->value.int32);
}
return result;
} else {
return arg->value.int32;
}
case GPGME_CONF_UINT32:
if (list) {
std::vector<unsigned int> result;
for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
result.push_back(a->value.uint32);
}
return result;
} else {
return arg->value.uint32;
}
case GPGME_CONF_FILENAME:
case GPGME_CONF_LDAP_SERVER:
case GPGME_CONF_KEY_FPR:
case GPGME_CONF_PUB_KEY:
case GPGME_CONF_SEC_KEY:
case GPGME_CONF_ALIAS_LIST:
// these should not happen in alt_type, but fall through
case GPGME_CONF_STRING:
if (list) {
std::vector<const char *> result;
for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
result.push_back(a->value.string);
}
return result;
} else {
return arg->value.string;
}
}
assert(!"Option: unknown alt_type!");
return Option::Variant();
}
namespace
{
inline const void *to_void_star(const char *s)
{
return s;
}
inline const void *to_void_star(const std::string &s)
{
return s.c_str();
}
inline const void *to_void_star(const int &i)
{
return &i; // const-&: sic!
}
inline const void *to_void_star(const unsigned int &i)
{
return &i; // const-&: sic!
}
struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> {
static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
{
gpgme_conf_arg_t arg = 0;
#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
return 0;
}
#else
if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) {
return 0;
}
#endif
else {
return arg;
}
}
gpgme_conf_arg_t operator()(bool v) const
{
return v ? make_argument(0) : 0 ;
}
gpgme_conf_arg_t operator()(const char *s) const
{
return make_argument(s ? s : "");
}
gpgme_conf_arg_t operator()(const std::string &s) const
{
return operator()(s.c_str());
}
gpgme_conf_arg_t operator()(int i) const
{
return make_argument(&i);
}
gpgme_conf_arg_t operator()(unsigned int i) const
{
return make_argument(&i);
}
template <typename T>
gpgme_conf_arg_t operator()(const std::vector<T> &value) const
{
gpgme_conf_arg_t result = 0;
gpgme_conf_arg_t last = 0;
for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
if (gpgme_conf_arg_t arg = make_argument(to_void_star(*it))) {
if (last) {
last = last->next = arg;
} else {
result = last = arg;
}
}
}
return result;
}
};
}
static gpgme_conf_arg_t variant_to_argument(const Option::Variant &value)
{
VariantToArgumentVisitor v;
return apply_visitor(v, value);
}
optional<Option::Variant> Option::defaultValue() const
{
if (isNull()) {
return optional<Variant>();
} else {
return argument_to_variant(opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value);
}
}
#endif
Argument Option::defaultValue() const
{
if (isNull()) {

View File

@ -98,7 +98,8 @@ public:
explicit Component(const shared_gpgme_conf_comp_t &gpgme_comp)
: comp(gpgme_comp) {}
Component(const Component &other) = default;
// copy ctor is ok
const Component &operator=(const Component &other)
{
if (this != &other) {
@ -148,7 +149,6 @@ public:
Option(const shared_gpgme_conf_comp_t &gpgme_comp, gpgme_conf_opt_t gpgme_opt)
: comp(gpgme_comp), opt(gpgme_opt) {}
Option(const Option &other) = default;
const Option &operator=(const Option &other)
{
if (this != &other) {
@ -190,7 +190,7 @@ public:
/*! The value that is in the config file (or null, if it's not set). */
Argument activeValue() const;
/*! The value that is in this object, i.e. either activeValue(), newValue(), or defaultValue() */
/*! The value that is in this object, ie. either activeValue(), newValue(), or defaultValue() */
Argument currentValue() const;
Argument newValue() const;

View File

@ -50,9 +50,7 @@
#include <gpgme.h>
#include <functional>
#include <istream>
#include <numeric>
#ifndef NDEBUG
#include <iostream>
using std::cerr;
@ -130,13 +128,6 @@ const char *Error::asString() const
return mMessage.c_str();
}
std::string Error::asStdString() const
{
std::string message;
format_error(static_cast<gpgme_error_t>(mErr), message);
return message;
}
int Error::code() const
{
return gpgme_err_code(mErr);
@ -149,18 +140,22 @@ int Error::sourceID() const
bool Error::isCanceled() const
{
return code() == GPG_ERR_CANCELED || code() == GPG_ERR_FULLY_CANCELED;
return code() == GPG_ERR_CANCELED;
}
int Error::toErrno() const
{
//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
//#else
// return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
//#endif
}
// static
bool Error::hasSystemError()
{
return gpgme_err_code_from_syserror() != GPG_ERR_MISSING_ERRNO ;
return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
}
// static
@ -195,20 +190,7 @@ Error Error::fromCode(unsigned int err, unsigned int src)
std::ostream &operator<<(std::ostream &os, const Error &err)
{
return os << "GpgME::Error(" << err.encodedError() << " (" << err.asStdString() << "))";
}
Context::KeyListModeSaver::KeyListModeSaver(Context *ctx)
: mCtx{ctx}
, mKeyListMode{ctx ? ctx->keyListMode() : 0}
{
}
Context::KeyListModeSaver::~KeyListModeSaver()
{
if (mCtx) {
mCtx->setKeyListMode(mKeyListMode);
}
return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
}
Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
@ -479,33 +461,9 @@ Error Context::setLocale(int cat, const char *val)
return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
}
static GpgME::EngineInfo get_engine_info(gpgme_engine_info_t engineInfos, gpgme_protocol_t protocol)
{
if (!engineInfos) {
return EngineInfo{};
}
for (gpgme_engine_info_t i = engineInfos ; i ; i = i->next) {
if (i->protocol == protocol) {
return EngineInfo{i};
}
}
return EngineInfo{};
}
static GpgME::EngineInfo get_static_engine_info(gpgme_protocol_t protocol)
{
gpgme_engine_info_t ei = nullptr;
if (gpgme_get_engine_info(&ei)) {
return EngineInfo{};
}
return get_engine_info(ei, protocol);
}
EngineInfo Context::engineInfo() const
{
return get_engine_info(gpgme_ctx_get_engine_info(d->ctx), gpgme_get_protocol(d->ctx));
return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
}
Error Context::setEngineFileName(const char *filename)
@ -538,25 +496,25 @@ const char *Context::getSender ()
Error Context::startKeyListing(const char *pattern, bool secretOnly)
{
d->lastop = (((keyListMode() & GpgME::Locate) == GpgME::Locate)
? Private::KeyListWithImport
: Private::KeyList);
d->lastop = Private::KeyList;
return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
}
Error Context::startKeyListing(const char *patterns[], bool secretOnly)
{
d->lastop = (((keyListMode() & GpgME::Locate) == GpgME::Locate)
? Private::KeyListWithImport
: Private::KeyList);
d->lastop = Private::KeyList;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return startKeyListing(patterns ? patterns[0] : nullptr, secretOnly);
}
#endif
return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
}
Key Context::nextKey(GpgME::Error &e)
{
d->lastop = (((keyListMode() & GpgME::Locate) == GpgME::Locate)
? Private::KeyListWithImport
: Private::KeyList);
d->lastop = Private::KeyList;
gpgme_key_t key = nullptr;
e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
return Key(key, false);
@ -605,137 +563,44 @@ KeyGenerationResult Context::keyGenerationResult() const
}
}
Error Context::exportKeys(const char *pattern, Data &keyData, unsigned int mode)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, mode, dp ? dp->data : nullptr));
}
Error Context::exportKeys(const char *patterns[], Data &keyData, unsigned int mode)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, mode, dp ? dp->data : nullptr));
}
Error Context::startKeyExport(const char *pattern, Data &keyData, unsigned int mode)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, mode, dp ? dp->data : nullptr));
}
Error Context::startKeyExport(const char *patterns[], Data &keyData, unsigned int mode)
{
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, mode, dp ? dp->data : nullptr));
}
Error Context::exportPublicKeys(const char *pattern, Data &keyData, unsigned int mode)
{
if (mode & (ExportSecret | ExportSecretSubkey)) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return exportKeys(pattern, keyData, mode);
}
Error Context::exportPublicKeys(const char *patterns[], Data &keyData, unsigned int mode)
{
if (mode & (ExportSecret | ExportSecretSubkey)) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return exportKeys(patterns, keyData, mode);
}
Error Context::startPublicKeyExport(const char *pattern, Data &keyData, unsigned int mode)
{
if (mode & (ExportSecret | ExportSecretSubkey)) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return startKeyExport(pattern, keyData, mode);
}
Error Context::startPublicKeyExport(const char *patterns[], Data &keyData, unsigned int mode)
{
if (mode & (ExportSecret | ExportSecretSubkey)) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return startKeyExport(patterns, keyData, mode);
}
/* Same as above but without mode */
Error Context::exportPublicKeys(const char *pattern, Data &keyData)
{
return exportPublicKeys(pattern, keyData, 0);
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, 0, dp ? dp->data : nullptr));
}
Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
{
return exportPublicKeys(patterns, keyData, 0);
d->lastop = Private::Export;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return exportPublicKeys(patterns ? patterns[0] : nullptr, keyData);
}
#endif
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, 0, dp ? dp->data : nullptr));
}
Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
{
return startPublicKeyExport(pattern, keyData, 0);
d->lastop = Private::Export;
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, 0, dp ? dp->data : nullptr));
}
Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
{
return startPublicKeyExport(patterns, keyData, 0);
}
Error Context::exportSecretKeys(const char *pattern, Data &keyData, unsigned int mode)
{
if (mode & ExportSecretSubkey) {
return Error::fromCode(GPG_ERR_INV_FLAG);
d->lastop = Private::Export;
#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
if (!patterns || !patterns[0] || !patterns[1]) {
// max. one pattern -> use the non-ext version
return startPublicKeyExport(patterns ? patterns[0] : nullptr, keyData);
}
return exportKeys(pattern, keyData, mode|ExportSecret);
}
Error Context::exportSecretKeys(const char *patterns[], Data &keyData, unsigned int mode)
{
if (mode & ExportSecretSubkey) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return exportKeys(patterns, keyData, mode|ExportSecret);
}
Error Context::startSecretKeyExport(const char *pattern, Data &keyData, unsigned int mode)
{
if (mode & ExportSecretSubkey) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return startKeyExport(pattern, keyData, mode|ExportSecret);
}
Error Context::startSecretKeyExport(const char *patterns[], Data &keyData, unsigned int mode)
{
if (mode & ExportSecretSubkey) {
return Error::fromCode(GPG_ERR_INV_FLAG);
}
return startKeyExport(patterns, keyData, mode|ExportSecret);
}
Error Context::exportSecretSubkeys(const char *pattern, Data &keyData, unsigned int mode)
{
return exportKeys(pattern, keyData, mode|ExportSecretSubkey);
}
Error Context::exportSecretSubkeys(const char *patterns[], Data &keyData, unsigned int mode)
{
return exportKeys(patterns, keyData, mode|ExportSecretSubkey);
}
Error Context::startSecretSubkeyExport(const char *pattern, Data &keyData, unsigned int mode)
{
return startKeyExport(pattern, keyData, mode|ExportSecretSubkey);
}
Error Context::startSecretSubkeyExport(const char *patterns[], Data &keyData, unsigned int mode)
{
return startKeyExport(patterns, keyData, mode|ExportSecretSubkey);
#endif
Data::Private *const dp = keyData.impl();
return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, 0, dp ? dp->data : nullptr));
}
ImportResult Context::importKeys(const Data &data)
@ -822,22 +687,6 @@ Error Context::startKeyImport(const std::vector<Key> &kk)
return err;
}
ImportResult Context::importKeys(const std::vector<std::string> &keyIds)
{
d->lastop = Private::Import;
const StringsToCStrings keyids{keyIds};
d->lasterr = gpgme_op_receive_keys(d->ctx, keyids.c_strs());
return ImportResult(d->ctx, Error(d->lasterr));
}
Error Context::startKeyImport(const std::vector<std::string> &keyIds)
{
d->lastop = Private::Import;
const StringsToCStrings keyids{keyIds};
d->lasterr = gpgme_op_receive_keys_start(d->ctx, keyids.c_strs());
return Error(d->lasterr);
}
ImportResult Context::importResult() const
{
if (d->lastop & Private::Import) {
@ -1073,7 +922,7 @@ DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText, const
const Data::Private *const cdp = cipherText.impl();
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags), cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr);
return decryptionResult();
return DecryptionResult(d->ctx, Error(d->lasterr));
}
DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
@ -1110,7 +959,7 @@ VerificationResult Context::verifyDetachedSignature(const Data &signature, const
const Data::Private *const sdp = signature.impl();
const Data::Private *const tdp = signedText.impl();
d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : nullptr, tdp ? tdp->data : nullptr, nullptr);
return verificationResult();
return VerificationResult(d->ctx, Error(d->lasterr));
}
VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
@ -1119,7 +968,7 @@ VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &
const Data::Private *const sdp = signedData.impl();
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : nullptr, nullptr, pdp ? pdp->data : nullptr);
return verificationResult();
return VerificationResult(d->ctx, Error(d->lasterr));
}
Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
@ -1141,18 +990,9 @@ Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &pl
VerificationResult Context::verificationResult() const
{
if (d->lastop & Private::Verify) {
const auto res = VerificationResult{d->ctx, Error(d->lasterr)};
if ((d->lastop == Private::DecryptAndVerify)
&& (res.error().code() == GPG_ERR_NO_DATA)
&& (res.numSignatures() > 0)) {
// ignore "no data" error for verification if there are signatures and
// the operation was a combined (tentative) decryption and verification
// because then "no data" just indicates that there was nothing to decrypt
return VerificationResult{d->ctx, Error{}};
}
return res;
return VerificationResult(d->ctx, Error(d->lasterr));
} else {
return {};
return VerificationResult();
}
}
@ -1163,7 +1003,8 @@ std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const
Data::Private *const pdp = plainText.impl();
d->lasterr = gpgme_op_decrypt_ext(d->ctx, static_cast<gpgme_decrypt_flags_t> (d->decryptFlags | flags | DecryptVerify),
cdp ? cdp->data : nullptr, pdp ? pdp->data : nullptr);
return std::make_pair(decryptionResult(), verificationResult());
return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
VerificationResult(d->ctx, Error(d->lasterr)));
}
std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
@ -1184,7 +1025,6 @@ Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Da
return startCombinedDecryptionAndVerification(cipherText, plainText, DecryptNone);
}
namespace {
unsigned int to_auditlog_flags(unsigned int flags)
{
unsigned int result = 0;
@ -1199,7 +1039,6 @@ unsigned int to_auditlog_flags(unsigned int flags)
}
return result;
}
}
Error Context::startGetAuditLog(Data &output, unsigned int flags)
{
@ -1289,25 +1128,14 @@ std::vector<Notation> Context::signatureNotations() const
return result;
}
static gpgme_sig_mode_t sigflags2sigflags(SignatureMode flags)
static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
{
unsigned int result = 0;
if (flags & SignatureMode::NormalSignatureMode) {
result |= GPGME_SIG_MODE_NORMAL;
switch (mode) {
default:
case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
case Detached: return GPGME_SIG_MODE_DETACH;
case Clearsigned: return GPGME_SIG_MODE_CLEAR;
}
if (flags & SignatureMode::Detached) {
result |= GPGME_SIG_MODE_DETACH;
}
if (flags & SignatureMode::Clearsigned) {
result |= GPGME_SIG_MODE_CLEAR;
}
if (flags & SignatureMode::SignArchive) {
result |= GPGME_SIG_MODE_ARCHIVE;
}
if (flags & SignatureMode::SignFile) {
result |= GPGME_SIG_MODE_FILE;
}
return static_cast<gpgme_sig_mode_t>(result);
}
SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
@ -1315,7 +1143,7 @@ SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMod
d->lastop = Private::Sign;
const Data::Private *const pdp = plainText.impl();
Data::Private *const sdp = signature.impl();
d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigflags2sigflags(mode));
d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigmode2sigmode(mode));
return SigningResult(d->ctx, Error(d->lasterr));
}
@ -1324,7 +1152,7 @@ Error Context::startSigning(const Data &plainText, Data &signature, SignatureMod
d->lastop = Private::Sign;
const Data::Private *const pdp = plainText.impl();
Data::Private *const sdp = signature.impl();
return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigflags2sigflags(mode)));
return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : nullptr, sdp ? sdp->data : nullptr, sigmode2sigmode(mode)));
}
SigningResult Context::signingResult() const
@ -1357,21 +1185,6 @@ static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags
if (flags & Context::Symmetric) {
result |= GPGME_ENCRYPT_SYMMETRIC;
}
if (flags & Context::ThrowKeyIds) {
result |= GPGME_ENCRYPT_THROW_KEYIDS;
}
if (flags & Context::EncryptWrap) {
result |= GPGME_ENCRYPT_WRAP;
}
if (flags & Context::WantAddress) {
result |= GPGME_ENCRYPT_WANT_ADDRESS;
}
if (flags & Context::EncryptArchive) {
result |= GPGME_ENCRYPT_ARCHIVE;
}
if (flags & Context::EncryptFile) {
result |= GPGME_ENCRYPT_FILE;
}
return static_cast<gpgme_encrypt_flags_t>(result);
}
@ -1507,11 +1320,6 @@ Error Context::cancelPendingOperation()
return Error(gpgme_cancel_async(d->ctx));
}
Error Context::cancelPendingOperationImmediately()
{
return Error(gpgme_cancel(d->ctx));
}
bool Context::poll()
{
gpgme_error_t e = GPG_ERR_NO_ERROR;
@ -1678,16 +1486,6 @@ Error Context::startRevUid(const Key &k, const char *userid)
k.impl(), userid, 0));
}
Error Context::setPrimaryUid(const Key &k, const char *userid)
{
return Error(d->lasterr = gpgme_op_set_uid_flag(d->ctx, k.impl(), userid, "primary", nullptr));
}
Error Context::startSetPrimaryUid(const Key &k, const char *userid)
{
return Error(d->lasterr = gpgme_op_set_uid_flag_start(d->ctx, k.impl(), userid, "primary", nullptr));
}
Error Context::createSubkey(const Key &k, const char *algo,
unsigned long reserved,
unsigned long expires,
@ -1706,112 +1504,6 @@ Error Context::startCreateSubkey(const Key &k, const char *algo,
k.impl(), algo, reserved, expires, flags));
}
static std::string getLFSeparatedListOfStrings(const std::vector<std::string> &strings)
{
if (strings.empty()) {
return std::string();
}
return std::accumulate(
std::next(strings.begin()),
strings.end(),
strings[0],
[](const std::string &a, const std::string &b) {
return a + '\n' + b;
}
);
}
static std::string getLFSeparatedListOfFingerprintsFromSubkeys(const std::vector<Subkey> &subkeys)
{
if (subkeys.empty()) {
return std::string();
}
std::vector<std::string> fprs;
fprs.reserve(subkeys.size());
for (auto &it : subkeys) {
if (it.fingerprint()) {
fprs.push_back(std::string(it.fingerprint()));
}
}
return getLFSeparatedListOfStrings(fprs);
}
Error Context::setExpire(const Key &k, unsigned long expires,
const std::vector<Subkey> &subkeys,
const Context::SetExpireFlags flags)
{
std::string subfprs;
if (flags & Context::SetExpireAllSubkeys) {
subfprs = "*";
} else {
subfprs = getLFSeparatedListOfFingerprintsFromSubkeys(subkeys);
}
return Error(d->lasterr = gpgme_op_setexpire(d->ctx,
k.impl(), expires, subfprs.c_str(), 0));
}
Error Context::startSetExpire(const Key &k, unsigned long expires,
const std::vector<Subkey> &subkeys,
const Context::SetExpireFlags flags)
{
std::string subfprs;
if (flags & Context::SetExpireAllSubkeys) {
subfprs = "*";
} else {
subfprs = getLFSeparatedListOfFingerprintsFromSubkeys(subkeys);
}
return Error(d->lasterr = gpgme_op_setexpire_start(d->ctx,
k.impl(), expires, subfprs.c_str(), 0));
}
static std::string getLFSeparatedListOfUserIds(const std::vector<UserID> &userIds)
{
if (userIds.empty()) {
return std::string();
}
std::vector<std::string> uids;
uids.reserve(userIds.size());
for (auto &userId : userIds) {
if (userId.id()) {
uids.push_back(std::string(userId.id()));
}
}
return getLFSeparatedListOfStrings(uids);
}
Error Context::revokeSignature(const Key &key, const Key &signingKey,
const std::vector<UserID> &userIds)
{
const unsigned int flags = userIds.size() > 1 ? GPGME_REVSIG_LFSEP : 0;
const std::string uids = getLFSeparatedListOfUserIds(userIds);
return Error(d->lasterr = gpgme_op_revsig(d->ctx,
key.impl(), signingKey.impl(), uids.c_str(), flags));
}
Error Context::startRevokeSignature(const Key &key, const Key &signingKey,
const std::vector<UserID> &userIds)
{
const unsigned int flags = userIds.size() > 1 ? GPGME_REVSIG_LFSEP : 0;
const std::string uids = getLFSeparatedListOfUserIds(userIds);
return Error(d->lasterr = gpgme_op_revsig_start(d->ctx,
key.impl(), signingKey.impl(), uids.c_str(), flags));
}
Error Context::addAdsk(const Key &k, const char *adsk)
{
return Error(d->lasterr = gpgme_op_createsubkey(d->ctx, k.impl(), adsk, 0, 0, GPGME_CREATE_ADSK));
}
Error Context::startAddAdsk(const Key &k, const char *adsk)
{
return Error(d->lasterr = gpgme_op_createsubkey_start(d->ctx, k.impl(), adsk, 0, 0, GPGME_CREATE_ADSK));
}
Error Context::setFlag(const char *name, const char *value)
{
return Error(d->lasterr = gpgme_set_ctx_flag(d->ctx, name, value));
@ -1923,9 +1615,6 @@ std::ostream &operator<<(std::ostream &os, KeyListMode mode)
CHECK(Validate);
CHECK(Ephemeral);
CHECK(WithTofu);
CHECK(WithKeygrip);
CHECK(WithSecret);
CHECK(ForceExtern);
#undef CHECK
return os << ')';
}
@ -1933,8 +1622,7 @@ std::ostream &operator<<(std::ostream &os, KeyListMode mode)
std::ostream &operator<<(std::ostream &os, SignatureMode mode)
{
os << "GpgME::SignatureMode(";
#undef CHECK
switch (mode & (NormalSignatureMode|Detached|Clearsigned)) {
switch (mode) {
#define CHECK( x ) case x: os << #x; break
CHECK(NormalSignatureMode);
CHECK(Detached);
@ -1944,10 +1632,6 @@ std::ostream &operator<<(std::ostream &os, SignatureMode mode)
os << "???" "(" << static_cast<int>(mode) << ')';
break;
}
#define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
CHECK(SignArchive);
CHECK(SignFile);
#undef CHECK
return os << ')';
}
@ -1961,11 +1645,6 @@ std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
CHECK(ExpectSign);
CHECK(NoCompress);
CHECK(Symmetric);
CHECK(ThrowKeyIds);
CHECK(EncryptWrap);
CHECK(WantAddress);
CHECK(EncryptArchive);
CHECK(EncryptFile);
#undef CHECK
return os << ')';
}
@ -1989,7 +1668,20 @@ GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
{
return get_static_engine_info(proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP);
gpgme_engine_info_t ei = nullptr;
if (gpgme_get_engine_info(&ei)) {
return EngineInfo();
}
const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
if (i->protocol == p) {
return EngineInfo(i);
}
}
return EngineInfo();
}
const char *GpgME::dirInfo(const char *what)
@ -2027,7 +1719,20 @@ static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
{
return get_static_engine_info(engine2protocol(engine));
gpgme_engine_info_t ei = nullptr;
if (gpgme_get_engine_info(&ei)) {
return EngineInfo();
}
const gpgme_protocol_t p = engine2protocol(engine);
for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
if (i->protocol == p) {
return EngineInfo(i);
}
}
return EngineInfo();
}
GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
@ -2086,8 +1791,3 @@ bool GpgME::hasFeature(unsigned long features, unsigned long features2)
&& features2 == (features2 & supported_features2)
;
}
int GpgME::setGlobalFlag(const char *name, const char *value)
{
return gpgme_set_global_flag(name, value);
}

View File

@ -27,11 +27,9 @@
#include "global.h"
#include "error.h"
#include "key.h"
#include "verificationresult.h" // for Signature::Notation
#include <memory>
#include <string>
#include <vector>
#include <utility>
#include <iosfwd>
@ -39,6 +37,7 @@
namespace GpgME
{
class Key;
class Data;
class TrustItem;
class ProgressProvider;
@ -64,17 +63,6 @@ class GPGMEPP_EXPORT Context
public:
//using GpgME::Protocol;
/// RAII-style class for saving/restoring the key list mode.
class GPGMEPP_EXPORT KeyListModeSaver
{
public:
explicit KeyListModeSaver(Context *ctx);
~KeyListModeSaver();
private:
Context *mCtx;
unsigned int mKeyListMode;
};
//
// Creation and destruction:
//
@ -194,42 +182,11 @@ public:
//
// Key Export
//
enum ExportMode {
ExportDefault = 0,
ExportExtern = 2,
ExportMinimal = 4,
ExportSecret = 16,
ExportRaw = 32,
ExportPKCS12 = 64,
ExportNoUID = 128, // obsolete; has no effect
ExportSSH = 256,
ExportSecretSubkey = 512,
};
GpgME::Error exportPublicKeys(const char *pattern, Data &keyData);
GpgME::Error exportPublicKeys(const char *pattern, Data &keyData, unsigned int mode);
GpgME::Error exportPublicKeys(const char *pattern[], Data &keyData);
GpgME::Error exportPublicKeys(const char *pattern[], Data &keyData, unsigned int mode);
GpgME::Error startPublicKeyExport(const char *pattern, Data &keyData);
GpgME::Error startPublicKeyExport(const char *pattern, Data &keyData, unsigned int mode);
GpgME::Error startPublicKeyExport(const char *pattern[], Data &keyData);
GpgME::Error startPublicKeyExport(const char *pattern[], Data &keyData, unsigned int mode);
GpgME::Error exportSecretKeys(const char *pattern, Data &keyData, unsigned int mode = ExportSecret);
GpgME::Error exportSecretKeys(const char *pattern[], Data &keyData, unsigned int mode = ExportSecret);
GpgME::Error startSecretKeyExport(const char *pattern, Data &keyData, unsigned int mode = ExportSecret);
GpgME::Error startSecretKeyExport(const char *pattern[], Data &keyData, unsigned int mode = ExportSecret);
GpgME::Error exportSecretSubkeys(const char *pattern, Data &keyData, unsigned int mode = ExportSecretSubkey);
GpgME::Error exportSecretSubkeys(const char *pattern[], Data &keyData, unsigned int mode = ExportSecretSubkey);
GpgME::Error startSecretSubkeyExport(const char *pattern, Data &keyData, unsigned int mode = ExportSecretSubkey);
GpgME::Error startSecretSubkeyExport(const char *pattern[], Data &keyData, unsigned int mode = ExportSecretSubkey);
// generic export functions; prefer using the specific public/secret key export functions
GpgME::Error exportKeys(const char *pattern, Data &keyData, unsigned int mode = ExportDefault);
GpgME::Error exportKeys(const char *pattern[], Data &keyData, unsigned int mode = ExportDefault);
GpgME::Error startKeyExport(const char *pattern, Data &keyData, unsigned int mode = ExportDefault);
GpgME::Error startKeyExport(const char *pattern[], Data &keyData, unsigned int mode = ExportDefault);
//
// Key Import
@ -237,10 +194,8 @@ public:
ImportResult importKeys(const Data &data);
ImportResult importKeys(const std::vector<Key> &keys);
ImportResult importKeys(const std::vector<std::string> &keyIds);
GpgME::Error startKeyImport(const Data &data);
GpgME::Error startKeyImport(const std::vector<Key> &keys);
GpgME::Error startKeyImport(const std::vector<std::string> &keyIds);
ImportResult importResult() const;
//
@ -295,9 +250,6 @@ public:
Error revUid(const Key &key, const char *userid);
Error startRevUid(const Key &key, const char *userid);
Error setPrimaryUid(const Key &key, const char *userid);
Error startSetPrimaryUid(const Key &key, const char *userid);
Error createSubkey(const Key &key, const char *algo,
unsigned long reserved = 0,
unsigned long expires = 0,
@ -307,26 +259,6 @@ public:
unsigned long expires = 0,
unsigned int flags = 0);
enum SetExpireFlags {
SetExpireDefault = 0,
SetExpireAllSubkeys = 1
};
Error setExpire(const Key &k, unsigned long expires,
const std::vector<Subkey> &subkeys = std::vector<Subkey>(),
const SetExpireFlags flags = SetExpireDefault);
Error startSetExpire(const Key &k, unsigned long expires,
const std::vector<Subkey> &subkeys = std::vector<Subkey>(),
const SetExpireFlags flags = SetExpireDefault);
Error revokeSignature(const Key &key, const Key &signingKey,
const std::vector<UserID> &userIds = std::vector<UserID>());
Error startRevokeSignature(const Key &key, const Key &signingKey,
const std::vector<UserID> &userIds = std::vector<UserID>());
Error addAdsk(const Key &k, const char *adsk);
Error startAddAdsk(const Key &k, const char *adsk);
// using TofuInfo::Policy
Error setTofuPolicy(const Key &k, unsigned int policy);
Error setTofuPolicyStart(const Key &k, unsigned int policy);
@ -373,7 +305,6 @@ public:
// Keep in line with core's flags
DecryptNone = 0,
DecryptVerify = 1,
DecryptArchive = 2,
DecryptUnwrap = 128,
DecryptMaxValue = 0x80000000
};
@ -451,10 +382,7 @@ public:
NoCompress = 16,
Symmetric = 32,
ThrowKeyIds = 64,
EncryptWrap = 128,
WantAddress = 256,
EncryptArchive = 512,
EncryptFile = 1024
EncryptWrap = 128
};
EncryptionResult encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
GpgME::Error encryptSymmetrically(const Data &plainText, Data &cipherText);
@ -530,7 +458,6 @@ public:
GpgME::Error wait();
GpgME::Error lastError() const;
GpgME::Error cancelPendingOperation();
GpgME::Error cancelPendingOperationImmediately();
class Private;
const Private *impl() const

View File

@ -1,7 +1,8 @@
/*
statusconsumer.h - Interface for status callbacks
Copyright (c) 2020 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
context_glib.cpp - wraps a gpgme key context, gpgme-glib-specific functions
Copyright (C) 2007 Klarälvdalens Datakonsult AB
2016 Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
This file is part of GPGME++.
@ -21,22 +22,20 @@
Boston, MA 02110-1301, USA.
*/
#ifndef __GPGMEPP_INTERFACES_STATUSCONSUMER_H__
#define __GPGMEPP_INTERFACES_STATUSCONSUMER_H__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "../gpgmepp_export.h"
#include <global.h>
namespace GpgME
extern "C" GIOChannel *gpgme_get_fdptr(int);
GIOChannel *GpgME::getGIOChannel(int fd)
{
return gpgme_get_fdptr(fd);
}
class GPGMEPP_EXPORT StatusConsumer
QIODevice *GpgME::getQIODevice(int fd)
{
public:
virtual ~StatusConsumer() {}
virtual void status(const char *status, const char *details) = 0;
};
} // namespace GpgME
#endif // __GPGMEPP_INTERFACES_STATUSCONSUMER_H__
return 0;
}

View File

@ -53,7 +53,6 @@ public:
KeyGen = 0x080,
KeyList = 0x100,
KeyListWithImport = KeyList | Import, // gpgme_keylist_result_t and gpgme_import_result_t
TrustList = 0x200, // no gpgme_trustlist_result_t, but nevertheless...
Edit = 0x400, // no gpgme_edit_result_t, but nevertheless...

View File

@ -1,7 +1,8 @@
/*
util.cpp - some internal helpers
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
context_qt.cpp - wraps a gpgme key context, gpgme-qt-specific functions
Copyright (C) 2007 Klarälvdalens Datakonsult AB
2016 Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
This file is part of GPGME++.
@ -25,23 +26,16 @@
#include "config.h"
#endif
#include "util.h"
#include <global.h>
#include <functional>
extern "C" QIODevice *gpgme_get_fdptr(int);
StringsToCStrings::StringsToCStrings(const std::vector<std::string>& v)
: m_strings{v}
GIOChannel *GpgME::getGIOChannel(int)
{
return 0;
}
const char **StringsToCStrings::c_strs() const
QIODevice *GpgME::getQIODevice(int fd)
{
if (m_cstrings.empty()) {
m_cstrings.reserve(m_strings.size() + 1);
std::transform(std::begin(m_strings), std::end(m_strings),
std::back_inserter(m_cstrings),
std::mem_fn(&std::string::c_str));
m_cstrings.push_back(nullptr);
}
return m_cstrings.data();
return gpgme_get_fdptr(fd);
}

View File

@ -217,11 +217,6 @@ GpgME::Error GpgME::Data::setFileName(const char *name)
return Error(gpgme_data_set_file_name(d->data, name));
}
GpgME::Error GpgME::Data::setFileName(const std::string &name)
{
return Error(gpgme_data_set_file_name(d->data, name.c_str()));
}
ssize_t GpgME::Data::read(void *buffer, size_t length)
{
return gpgme_data_read(d->data, buffer, length);
@ -261,8 +256,6 @@ std::vector<GpgME::Key> GpgME::Data::toKeys(Protocol proto) const
while (!gpgme_op_keylist_next (ctx->impl()->ctx, &key)) {
ret.push_back(GpgME::Key(key, false));
}
gpgme_data_seek (d->data, 0, SEEK_SET);
delete ctx;
return ret;
}
@ -280,14 +273,3 @@ std::string GpgME::Data::toString()
seek (0, SEEK_SET);
return ret;
}
GpgME::Error GpgME::Data::setFlag(const char *name, const char *value)
{
return Error(gpgme_data_set_flag(d->data, name, value));
}
GpgME::Error GpgME::Data::setSizeHint(uint64_t size)
{
const std::string val = std::to_string(size);
return Error(gpgme_data_set_flag(d->data, "size-hint", val.c_str()));
}

View File

@ -27,7 +27,6 @@
#include "key.h"
#include <sys/types.h> // for size_t, off_t
#include <cstdint> // unit64_t
#include <cstdio> // FILE
#include <algorithm>
#include <memory>
@ -61,7 +60,6 @@ public:
static const Null null;
Data(const Data &other) = default;
const Data &operator=(Data other)
{
swap(other);
@ -107,7 +105,6 @@ public:
char *fileName() const;
Error setFileName(const char *name);
Error setFileName(const std::string &name);
ssize_t read(void *buffer, size_t length);
ssize_t write(const void *buffer, size_t length);
@ -123,12 +120,6 @@ public:
/** Return a copy of the data as std::string. Sets seek pos to 0 */
std::string toString();
/** See gpgme_data_set_flag */
Error setFlag(const char *name, const char *value);
/** Set a size hint for this data e.g. for progress calculations. */
Error setSizeHint(uint64_t size);
class Private;
Private *impl()
{

View File

@ -122,11 +122,6 @@ bool GpgME::DecryptionResult::isDeVs() const
return d && d->res.is_de_vs;
}
bool GpgME::DecryptionResult::isMime() const
{
return d && d->res.is_mime;
}
const char *GpgME::DecryptionResult::fileName() const
{
return d ? d->res.file_name : nullptr ;

View File

@ -47,7 +47,6 @@ public:
DecryptionResult(gpgme_ctx_t ctx, const Error &err);
explicit DecryptionResult(const Error &err);
DecryptionResult(const DecryptionResult &other) = default;
const DecryptionResult &operator=(DecryptionResult other)
{
swap(other);
@ -75,7 +74,6 @@ public:
}
bool isWrongKeyUsage() const;
bool isDeVs() const;
bool isMime() const;
const char *fileName() const;
@ -105,7 +103,6 @@ public:
Recipient();
explicit Recipient(gpgme_recipient_t reci);
Recipient(const Recipient &other) = default;
const Recipient &operator=(Recipient other)
{
swap(other);

View File

@ -30,6 +30,8 @@
#include "error.h"
#include "data.h"
#include <sstream>
using namespace GpgME;
DefaultAssuanTransaction::DefaultAssuanTransaction()

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
#define __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
#include "interfaces/assuantransaction.h"
#include <interfaces/assuantransaction.h>
#include <string>
#include <vector>

View File

@ -29,7 +29,6 @@
#include "editinteractor.h"
#include "callbacks.h"
#include "error.h"
#include "util.h"
#include <gpgme.h>
@ -42,7 +41,6 @@
#include <cerrno>
#include <cstring>
#include <cstdlib>
#ifndef GPG_ERR_ALREADY_SIGNED
# define GPG_ERR_ALREADY_SIGNED GPG_ERR_USER_1
@ -52,7 +50,6 @@ using namespace GpgME;
static const char *status_to_string(unsigned int status);
static Error status_to_error(unsigned int status);
static Error parse_sc_op_failure(const char *args);
class EditInteractor::Private
{
@ -64,10 +61,9 @@ public:
~Private();
private:
unsigned int state = StartState;
unsigned int state;
Error error;
std::FILE *debug = nullptr;
bool debugNeedsClosing = false;
std::FILE *debug;
};
class GpgME::CallbackHelper
@ -97,24 +93,12 @@ public:
// advance to next state based on input:
const unsigned int oldState = ei->state;
if (ei->q->needsNoResponse(status)) {
// keep state
} else if (status == GPGME_STATUS_ERROR) {
err = ei->q->parseStatusError(args);
ei->state = EditInteractor::ErrorState;
} else if (status == GPGME_STATUS_SC_OP_FAILURE) {
err = parse_sc_op_failure(args);
ei->state = EditInteractor::ErrorState;
} else {
ei->state = ei->q->nextState(status, args, err);
}
ei->state = ei->q->nextState(status, args, err);
if (ei->debug) {
std::fprintf(ei->debug, "EditInteractor: %u -> nextState( %s, %s ) -> %u\n",
oldState, status_to_string(status), args ? args : "<null>", ei->state);
}
if (err || err.isCanceled()) {
if (err) {
ei->state = oldState;
goto error;
}
@ -138,7 +122,7 @@ public:
if (writeAll(fd, result, len) != len) {
err = Error::fromSystemError();
if (ei->debug) {
std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asStdString().c_str());
std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
}
goto error;
}
@ -147,7 +131,7 @@ public:
if (writeAll(fd, "\n", 1) != 1) {
err = Error::fromSystemError();
if (ei->debug) {
std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asStdString().c_str());
std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
}
goto error;
}
@ -167,7 +151,7 @@ public:
}
error:
if (err || err.isCanceled()) {
if (err) {
ei->error = err;
ei->state = EditInteractor::ErrorState;
}
@ -189,28 +173,15 @@ static gpgme_error_t edit_interactor_callback(void *opaque, gpgme_status_code_t
const gpgme_edit_cb_t GpgME::edit_interactor_callback = ::edit_interactor_callback;
EditInteractor::Private::Private(EditInteractor *qq)
: q(qq)
: q(qq),
state(StartState),
error(),
debug(nullptr)
{
const char *debug_env = std::getenv("GPGMEPP_INTERACTOR_DEBUG");
if (!debug_env) {
return;
}
if (!strcmp(debug_env, "stdout")) {
debug = stdout;
} else if (!strcmp(debug_env, "stderr")) {
debug = stderr;
} else if (debug_env) {
debug = std::fopen(debug_env, "a+");
debugNeedsClosing = true;
}
}
EditInteractor::Private::~Private()
{
if (debug && debugNeedsClosing) {
std::fclose(debug);
}
}
EditInteractor::Private::~Private() {}
EditInteractor::EditInteractor()
: d(new Private(this))
@ -270,52 +241,6 @@ void EditInteractor::setDebugChannel(std::FILE *debug)
d->debug = debug;
}
GpgME::Error EditInteractor::parseStatusError(const char *args)
{
Error err;
const auto fields = split(args, ' ');
if (fields.size() >= 2) {
err = Error{static_cast<unsigned int>(std::stoul(fields[1]))};
} else {
err = Error::fromCode(GPG_ERR_GENERAL);
}
return err;
}
static Error sc_op_failure_to_error(unsigned int status)
{
switch (status) {
case 1:
// GPG_ERR_CANCELED or GPG_ERR_FULLY_CANCELED
return Error::fromCode(GPG_ERR_CANCELED);
case 2:
// GPG_ERR_BAD_PIN or GPG_ERR_BAD_RESET_CODE [sic]
return Error::fromCode(GPG_ERR_BAD_PIN);
case 3:
return Error::fromCode(GPG_ERR_PIN_BLOCKED);
case 4:
return Error::fromCode(GPG_ERR_NO_RESET_CODE);
}
return Error::fromCode(GPG_ERR_CARD);
}
// static
Error parse_sc_op_failure(const char *args)
{
Error err;
const auto fields = split(args, ' ');
if (fields.size() >= 1) {
err = sc_op_failure_to_error(static_cast<unsigned int>(std::stoul(fields[0])));
} else {
err = Error::fromCode(GPG_ERR_CARD);
}
return err;
}
static const char *const status_strings[] = {
"EOF",
/* mkstatus processing starts here */

View File

@ -60,9 +60,6 @@ public:
void setDebugChannel(std::FILE *file);
protected:
Error parseStatusError(const char *args);
private:
class Private;
Private *const d;

View File

@ -48,7 +48,6 @@ public:
EncryptionResult(gpgme_ctx_t ctx, const Error &error);
EncryptionResult(const Error &err);
EncryptionResult(const EncryptionResult &other) = default;
const EncryptionResult &operator=(EncryptionResult other)
{
swap(other);
@ -84,7 +83,6 @@ class GPGMEPP_EXPORT InvalidRecipient
public:
InvalidRecipient();
InvalidRecipient(const InvalidRecipient &other) = default;
const InvalidRecipient &operator=(InvalidRecipient other)
{
swap(other);

View File

@ -69,76 +69,6 @@ public:
}
}
bool operator < (const Version& other) const
{
if (major > other.major ||
(major == other.major && minor > other.minor) ||
(major == other.major && minor == other.minor && patch > other.patch) ||
(major >= other.major && minor >= other.minor && patch >= other.patch)) {
return false;
}
return true;
}
bool operator < (const char* other) const
{
return operator<(Version(other));
}
bool operator <= (const Version &other) const
{
return !operator>(other);
}
bool operator <= (const char *other) const
{
return operator<=(Version(other));
}
bool operator > (const char* other) const
{
return operator>(Version(other));
}
bool operator > (const Version & other) const
{
return !operator<(other) && !operator==(other);
}
bool operator >= (const Version &other) const
{
return !operator<(other);
}
bool operator >= (const char *other) const
{
return operator>=(Version(other));
}
bool operator == (const Version& other) const
{
return major == other.major
&& minor == other.minor
&& patch == other.patch;
}
bool operator == (const char* other) const
{
return operator==(Version(other));
}
bool operator != (const Version &other) const
{
return !operator==(other);
}
bool operator != (const char *other) const
{
return operator!=(Version(other));
}
// the non-const overloads of the comparison operators are kept for
// binary compatibility
bool operator < (const Version& other)
{
if (major > other.major ||
@ -155,36 +85,15 @@ public:
return operator<(Version(other));
}
bool operator <= (const Version &other)
{
return !operator>(other);
}
bool operator <= (const char *other)
{
return operator<=(Version(other));
}
bool operator > (const char* other)
{
return operator>(Version(other));
return !operator<(Version(other));
}
bool operator > (const Version & other)
{
return !operator<(other) && !operator==(other);
}
bool operator >= (const Version &other)
{
return !operator<(other);
}
bool operator >= (const char *other)
{
return operator>=(Version(other));
}
bool operator == (const Version& other)
{
return major == other.major
@ -197,16 +106,6 @@ public:
return operator==(Version(other));
}
bool operator != (const Version &other)
{
return !operator==(other);
}
bool operator != (const char *other)
{
return operator!=(Version(other));
}
friend std::ostream& operator << (std::ostream& stream, const Version& ver)
{
stream << ver.major;
@ -221,7 +120,6 @@ public:
EngineInfo();
explicit EngineInfo(gpgme_engine_info_t engine);
EngineInfo(const EngineInfo &other) = default;
const EngineInfo &operator=(EngineInfo other)
{
swap(other);

View File

@ -47,11 +47,7 @@ public:
explicit Error(unsigned int e) : mErr(e), mMessage() {}
const char *source() const;
/* This function is deprecated. Use asStdString() instead. asString() may
* return wrongly encoded (i.e. not UTF-8) results on Windows for the main
* thread if the function was first called from a secondary thread. */
GPGMEPP_DEPRECATED const char *asString() const;
std::string asStdString() const;
const char *asString() const;
int code() const;
int sourceID() const;

View File

@ -60,34 +60,15 @@ enum Engine { GpgEngine, GpgSMEngine, GpgConfEngine, UnknownEngine, AssuanEngine
enum KeyListMode {
Local = 0x1,
Extern = 0x2,
Locate = Local|Extern,
Locate = 0x3,
Signatures = 0x4,
SignatureNotations = 0x8,
Validate = 0x10,
Ephemeral = 0x20,
WithTofu = 0x40,
WithKeygrip = 0x80,
WithSecret = 0x100,
ForceExtern = 0x200,
LocateExternal = Locate|ForceExtern,
KeyListModeMask = 0x3ff
WithTofu = 0x40
};
enum SignatureMode {
NormalSignatureMode = 0,
Detached = 1,
Clearsigned = 2,
SignArchive = 4,
SignFile = 8,
};
enum class RevocationReason {
Unspecified = 0,
Compromised = 1,
Superseded = 2,
NoLongerUsed = 3
};
enum SignatureMode { NormalSignatureMode, Detached, Clearsigned };
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Protocol proto);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Engine eng);
@ -108,8 +89,7 @@ GPGMEPP_EXPORT EngineInfo engineInfo(Engine engine);
homedir, sysconfdir, bindir, libexecdir, libdir,
datadir, localedir, agent-socket, agent-ssh-socket,
dirmngr-socket, uiserver-socket, gpgconf-name, gpg-name,
gpgsm-name, g13-name, keyboxd-name, agent-name, scdaemon-name,
dirmngr-name, pinentry-name, socketdir, gpg-wks-client-name, gpgtar-name.
gpgsm-name, g13-name
This may be extended in the future.
*/
@ -118,9 +98,6 @@ GPGMEPP_EXPORT const char *dirInfo(const char *what);
GPGMEPP_EXPORT Error checkEngine(Protocol proto);
GPGMEPP_EXPORT Error checkEngine(Engine engine);
/* Wrapper for gpgme_set_global_flag */
GPGMEPP_EXPORT int setGlobalFlag(const char *name, const char *value);
GPGMEPP_EXPORT GIOChannel *getGIOChannel(int fd);
GPGMEPP_EXPORT QIODevice *getQIODevice(int fd);

View File

@ -1,205 +0,0 @@
/*
gpgaddexistingsubkeyeditinteractor.cpp - Edit Interactor to add an existing subkey to an OpenPGP key
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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 "gpgaddexistingsubkeyeditinteractor.h"
#include "error.h"
#include <gpgme.h>
// avoid conflict (msvc)
#ifdef ERROR
# undef ERROR
#endif
using namespace GpgME;
class GpgAddExistingSubkeyEditInteractor::Private
{
enum {
START = EditInteractor::StartState,
COMMAND,
ADD_EXISTING_KEY,
KEYGRIP,
FLAGS,
VALID,
KEY_CREATED,
QUIT,
SAVE,
ERROR = EditInteractor::ErrorState
};
GpgAddExistingSubkeyEditInteractor *const q = nullptr;
public:
Private(GpgAddExistingSubkeyEditInteractor *q, const std::string &keygrip)
: q{q}
, keygrip{keygrip}
{
}
const char *action(Error &err) const;
unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
std::string keygrip;
std::string expiry;
};
const char *GpgAddExistingSubkeyEditInteractor::Private::action(Error &err) const
{
switch (q->state()) {
case COMMAND:
return "addkey";
case ADD_EXISTING_KEY:
return "keygrip";
case KEYGRIP:
return keygrip.c_str();
case FLAGS:
return "Q"; // do not toggle any usage flags
case VALID:
return expiry.empty() ? "0" : expiry.c_str();
case QUIT:
return "quit";
case SAVE:
return "Y";
case START:
case KEY_CREATED:
case ERROR:
return nullptr;
default:
err = Error::fromCode(GPG_ERR_GENERAL);
return nullptr;
}
}
unsigned int GpgAddExistingSubkeyEditInteractor::Private::nextState(unsigned int status, const char *args, Error &err) const
{
using std::strcmp;
static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
static const Error NO_KEY_ERROR = Error::fromCode(GPG_ERR_NO_KEY);
static const Error INV_TIME_ERROR = Error::fromCode(GPG_ERR_INV_TIME);
switch (q->state()) {
case START:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case COMMAND:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.algo") == 0) {
return ADD_EXISTING_KEY;
}
err = GENERAL_ERROR;
return ERROR;
case ADD_EXISTING_KEY:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.keygrip") == 0) {
return KEYGRIP;
}
err = GENERAL_ERROR;
return ERROR;
case KEYGRIP:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.flags") == 0) {
return FLAGS;
} else if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.keygrip") == 0) {
err = NO_KEY_ERROR;
return ERROR;
}
err = GENERAL_ERROR;
return ERROR;
case FLAGS:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.valid") == 0) {
return VALID;
}
err = GENERAL_ERROR;
return ERROR;
case VALID:
if (status == GPGME_STATUS_KEY_CREATED) {
return KEY_CREATED;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return QUIT;
} else if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.valid") == 0) {
err = INV_TIME_ERROR;
return ERROR;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_CREATED:
return QUIT;
case QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
strcmp(args, "keyedit.save.okay") == 0) {
return SAVE;
}
err = GENERAL_ERROR;
return ERROR;
case ERROR:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return QUIT;
}
err = q->lastError();
return ERROR;
default:
err = GENERAL_ERROR;
return ERROR;
}
}
GpgAddExistingSubkeyEditInteractor::GpgAddExistingSubkeyEditInteractor(const std::string &keygrip)
: EditInteractor{}
, d{new Private{this, keygrip}}
{
}
GpgAddExistingSubkeyEditInteractor::~GpgAddExistingSubkeyEditInteractor() = default;
void GpgAddExistingSubkeyEditInteractor::setExpiry(const std::string &timeString)
{
d->expiry = timeString;
}
const char *GpgAddExistingSubkeyEditInteractor::action(Error &err) const
{
return d->action(err);
}
unsigned int GpgAddExistingSubkeyEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
{
return d->nextState(status, args, err);
}

View File

@ -1,59 +0,0 @@
/*
gpgaddexistingsubkeyeditinteractor.h - Edit Interactor to add an existing subkey to an OpenPGP key
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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.
*/
#ifndef __GPGMEPP_GPGADDEXISTINGSUBKEYEDITINTERACTOR_H__
#define __GPGMEPP_GPGADDEXISTINGSUBKEYEDITINTERACTOR_H__
#include "editinteractor.h"
#include <memory>
namespace GpgME
{
class GPGMEPP_EXPORT GpgAddExistingSubkeyEditInteractor : public EditInteractor
{
public:
/** Edit interactor to add the existing subkey with keygrip \a keygrip
* to the key a key edit operation is working on.
**/
explicit GpgAddExistingSubkeyEditInteractor(const std::string &keygrip);
~GpgAddExistingSubkeyEditInteractor() override;
/** Sets the validity period of the added subkey. Use "0" for no expiration
* or a simplified ISO date string ("yyyymmddThhmmss") for setting an
* expiration date. */
void setExpiry(const std::string &timeString);
private:
const char *action(Error &err) const override;
unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const override;
private:
class Private;
const std::unique_ptr<Private> d;
};
} // namespace GpgME
#endif // __GPGMEPP_GPGADDEXISTINGSUBKEYEDITINTERACTOR_H__

View File

@ -120,6 +120,10 @@ unsigned int GpgAddUserIDEditInteractor::nextState(unsigned int status, const ch
static const Error INV_EMAIL_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
if (needsNoResponse(status)) {
return state();
}
using namespace GpgAddUserIDEditInteractor_Private;
switch (state()) {

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
#define __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
#include "editinteractor.h"
#include <editinteractor.h>
#include <string>

View File

@ -33,6 +33,8 @@
#include <assert.h>
#include <sstream>
using namespace GpgME;
GpgAgentGetInfoAssuanTransaction::GpgAgentGetInfoAssuanTransaction(InfoItem item)

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
#define __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
#include "interfaces/assuantransaction.h"
#include <interfaces/assuantransaction.h>
#include <string>
#include <vector>

View File

@ -36,17 +36,15 @@ using namespace GpgME;
class GpgGenCardKeyInteractor::Private
{
public:
Private() : keysize("2048")
Private() : keysize("2048"), backup(false)
{
}
}
std::string name, email, backupFileName, expiry, serial, keysize;
bool backup = false;
Algo algo = RSA;
std::string curve;
bool backup;
};
GpgGenCardKeyInteractor::~GpgGenCardKeyInteractor() = default;
GpgGenCardKeyInteractor::~GpgGenCardKeyInteractor() {}
GpgGenCardKeyInteractor::GpgGenCardKeyInteractor(const std::string &serial):
d(new Private)
@ -84,20 +82,6 @@ std::string GpgGenCardKeyInteractor::backupFileName() const
return d->backupFileName;
}
void GpgGenCardKeyInteractor::setAlgo(Algo algo)
{
d->algo = algo;
}
void GpgGenCardKeyInteractor::setCurve(Curve curve)
{
if (curve == DefaultCurve) {
d->curve.clear();
} else if (curve >= 1 && curve <= LastCurve) {
d->curve = std::to_string(static_cast<int>(curve));
}
}
namespace GpgGenCardKeyInteractor_Private
{
enum {
@ -120,14 +104,6 @@ enum {
QUIT,
SAVE,
KEY_ATTR,
KEY_ALGO1,
KEY_ALGO2,
KEY_ALGO3,
KEY_CURVE1,
KEY_CURVE2,
KEY_CURVE3,
ERROR = EditInteractor::ErrorState
};
}
@ -142,16 +118,6 @@ const char *GpgGenCardKeyInteractor::action(Error &err) const
return "admin";
case COMMAND:
return "generate";
case KEY_ATTR:
return "key-attr";
case KEY_ALGO1:
case KEY_ALGO2:
case KEY_ALGO3:
return d->algo == RSA ? "1" : "2";
case KEY_CURVE1:
case KEY_CURVE2:
case KEY_CURVE3:
return d->curve.empty() ? "1" : d->curve.c_str(); // default is Curve25519
case NAME:
return d->name.c_str();
case EMAIL:
@ -192,6 +158,10 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
static const Error INV_EMAIL_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
if (needsNoResponse(status)) {
return state();
}
using namespace GpgGenCardKeyInteractor_Private;
switch (state()) {
@ -221,92 +191,12 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
err = GENERAL_ERROR;
return ERROR;
case DO_ADMIN:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return KEY_ATTR;
}
err = GENERAL_ERROR;
return ERROR;
// Handling for key-attr subcommand
case KEY_ATTR:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
// Happens if key attr is not yet supported.
return COMMAND;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO1;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_ALGO1:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.size") == 0) {
return SIZE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.curve") == 0) {
return KEY_CURVE1;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_ALGO2:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.size") == 0) {
return SIZE2;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.curve") == 0) {
return KEY_CURVE2;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_ALGO3:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.size") == 0) {
return SIZE3;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.curve") == 0) {
return KEY_CURVE3;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_CURVE1:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO2;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_CURVE2:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO3;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case KEY_CURVE3:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO3;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
// End key-attr handling
case COMMAND:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.backup_enc") == 0) {
@ -323,21 +213,14 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
strcmp(args, "cardedit.genkeys.size") == 0) {
return SIZE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.valid") == 0) {
return EXPIRE;
}
err = GENERAL_ERROR;
return ERROR;
case REPLACE:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.size") == 0) {
printf("Moving to SIZE\n");
return SIZE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keygen.valid") == 0) {
return EXPIRE;
}
err = GENERAL_ERROR;
return ERROR;
case SIZE:
@ -349,14 +232,6 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
strcmp(args, "keygen.valid") == 0) {
return EXPIRE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO2;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case SIZE2:
@ -368,14 +243,6 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
strcmp(args, "keygen.valid") == 0) {
return EXPIRE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.genkeys.algo") == 0) {
return KEY_ALGO3;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case SIZE3:
@ -383,10 +250,6 @@ unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char
strcmp(args, "keygen.valid") == 0) {
return EXPIRE;
}
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "cardedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case EXPIRE:

View File

@ -24,7 +24,7 @@
#ifndef __GPGMEPP_GPGGENCARDKEYEDITINTERACTOR_H__
#define __GPGMEPP_GPGGENCARDKEYEDITINTERACTOR_H__
#include "editinteractor.h"
#include <editinteractor.h>
#include <string>
#include <memory>
@ -56,29 +56,6 @@ public:
void setDoBackup(bool value);
void setExpiry(const std::string &timeString);
enum Algo {
RSA = 1,
ECC = 2,
};
void setAlgo(Algo algo);
// the enum values minus 1 have to match the indexes of the curves used by
// ask_curve() in gnupg's g10/keygen.c
enum Curve {
DefaultCurve = 0, // currently Curve25519
Curve25519 = 1,
Curve448,
NISTP256,
NISTP384,
NISTP521,
BrainpoolP256,
BrainpoolP384,
BrainpoolP512,
Secp256k1,
LastCurve = Secp256k1,
};
void setCurve(Curve curve);
std::string backupFileName() const;
private:

View File

@ -75,7 +75,4 @@ typedef struct _gpgme_tofu_info *gpgme_tofu_info_t;
struct _gpgme_op_query_swdb_result;
typedef struct _gpgme_op_query_swdb_result *gpgme_query_swdb_result_t;
struct _gpgme_revocation_key;
typedef struct _gpgme_revocation_key *gpgme_revocation_key_t;
#endif // __GPGMEPP_GPGMEFW_H__

View File

@ -1,207 +0,0 @@
/*
gpgrevokekeyeditinteractor.cpp - Edit Interactor to revoke own OpenPGP keys
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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 "gpgrevokekeyeditinteractor.h"
#include "error.h"
#include <gpgme.h>
#include <vector>
// avoid conflict (msvc)
#ifdef ERROR
# undef ERROR
#endif
using namespace GpgME;
class GpgRevokeKeyEditInteractor::Private
{
enum {
START = EditInteractor::StartState,
COMMAND,
CONFIRM_REVOKING_ENTIRE_KEY,
REASON_CODE,
REASON_TEXT,
// all these free slots belong to REASON_TEXT, too; we increase state()
// by one for each line of text, so that action() is called
REASON_TEXT_DONE = REASON_TEXT + 1000,
CONFIRM_REASON,
QUIT,
CONFIRM_SAVE,
ERROR = EditInteractor::ErrorState
};
GpgRevokeKeyEditInteractor *const q = nullptr;
public:
Private(GpgRevokeKeyEditInteractor *q)
: q{q}
, reasonCode{"0"}
{
}
const char *action(Error &err) const;
unsigned int nextState(unsigned int statusCode, const char *args, Error &err);
std::string reasonCode;
std::vector<std::string> reasonLines;
int nextLine = -1;
};
const char *GpgRevokeKeyEditInteractor::Private::action(Error &err) const
{
switch (const auto state = q->state()) {
case COMMAND:
return "revkey";
case CONFIRM_REVOKING_ENTIRE_KEY:
return "Y";
case REASON_CODE:
return reasonCode.c_str();
case REASON_TEXT_DONE:
return "";
case CONFIRM_REASON:
return "Y";
case QUIT:
return "quit";
case CONFIRM_SAVE:
return "Y";
case START:
return nullptr;
default:
if (state >= REASON_TEXT && state < REASON_TEXT_DONE) {
return reasonLines[nextLine].c_str();
}
// fall through
case ERROR:
err = Error::fromCode(GPG_ERR_GENERAL);
return nullptr;
}
}
unsigned int GpgRevokeKeyEditInteractor::Private::nextState(unsigned int status, const char *args, Error &err)
{
using std::strcmp;
static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
switch (const auto state = q->state()) {
case START:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return COMMAND;
}
err = GENERAL_ERROR;
return ERROR;
case COMMAND:
if (status == GPGME_STATUS_GET_BOOL &&
strcmp(args, "keyedit.revoke.subkey.okay") == 0) {
return CONFIRM_REVOKING_ENTIRE_KEY;
}
err = GENERAL_ERROR;
return ERROR;
case CONFIRM_REVOKING_ENTIRE_KEY:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "ask_revocation_reason.code") == 0) {
return REASON_CODE;
}
err = GENERAL_ERROR;
return ERROR;
case REASON_CODE:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "ask_revocation_reason.text") == 0) {
nextLine++;
return static_cast<std::size_t>(nextLine) < reasonLines.size() ? REASON_TEXT : REASON_TEXT_DONE;
}
err = GENERAL_ERROR;
return ERROR;
default:
if (state >= REASON_TEXT && state < REASON_TEXT_DONE) {
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "ask_revocation_reason.text") == 0) {
nextLine++;
return static_cast<std::size_t>(nextLine) < reasonLines.size() ? state + 1 : REASON_TEXT_DONE;
}
}
err = GENERAL_ERROR;
return ERROR;
case REASON_TEXT_DONE:
if (status == GPGME_STATUS_GET_BOOL &&
strcmp(args, "ask_revocation_reason.okay") == 0) {
return CONFIRM_REASON;
}
err = GENERAL_ERROR;
return ERROR;
case CONFIRM_REASON:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return QUIT;
}
err = GENERAL_ERROR;
return ERROR;
case QUIT:
if (status == GPGME_STATUS_GET_BOOL &&
strcmp(args, "keyedit.save.okay") == 0) {
return CONFIRM_SAVE;
}
err = GENERAL_ERROR;
return ERROR;
case ERROR:
if (status == GPGME_STATUS_GET_LINE &&
strcmp(args, "keyedit.prompt") == 0) {
return QUIT;
}
err = q->lastError();
return ERROR;
}
}
GpgRevokeKeyEditInteractor::GpgRevokeKeyEditInteractor()
: EditInteractor{}
, d{new Private{this}}
{
}
GpgRevokeKeyEditInteractor::~GpgRevokeKeyEditInteractor() = default;
void GpgRevokeKeyEditInteractor::setReason(RevocationReason reason, const std::vector<std::string> &description)
{
d->reasonCode = std::to_string(static_cast<int>(reason));
d->reasonLines = description;
}
const char *GpgRevokeKeyEditInteractor::action(Error &err) const
{
return d->action(err);
}
unsigned int GpgRevokeKeyEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
{
return d->nextState(status, args, err);
}

View File

@ -1,62 +0,0 @@
/*
gpgrevokekeyeditinteractor.h - Edit Interactor to revoke own OpenPGP keys
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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.
*/
#ifndef __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__
#define __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__
#include "editinteractor.h"
#include "global.h"
#include <memory>
#include <vector>
namespace GpgME
{
/** Edit interactor to revoke the key a key edit operation is working on.
* Supports revocation of own keys only. */
class GPGMEPP_EXPORT GpgRevokeKeyEditInteractor : public EditInteractor
{
public:
GpgRevokeKeyEditInteractor();
~GpgRevokeKeyEditInteractor() override;
/** Sets the reason for the revocation. The reason defaults to \c Unspecified.
* \a description can be used for adding a comment for the revocation. The
* individual elements of \a description must be non-empty strings and they
* must not contain any endline characters.
*/
void setReason(RevocationReason reason, const std::vector<std::string> &description = {});
private:
const char *action(Error &err) const override;
unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const override;
private:
class GPGMEPP_NO_EXPORT Private;
const std::unique_ptr<Private> d;
};
} // namespace GpgME
#endif // __GPGMEPP_GPGREVOKEKEYEDITINTERACTOR_H__

View File

@ -94,6 +94,10 @@ unsigned int GpgSetExpiryTimeEditInteractor::nextState(unsigned int status, cons
static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
static const Error INV_TIME_ERROR = Error::fromCode(GPG_ERR_INV_TIME);
if (needsNoResponse(status)) {
return state();
}
using namespace GpgSetExpiryTimeEditInteractor_Private;
switch (state()) {

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
#define __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
#include "editinteractor.h"
#include <editinteractor.h>
#include <string>

View File

@ -98,6 +98,10 @@ unsigned int GpgSetOwnerTrustEditInteractor::nextState(unsigned int status, cons
static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
//static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
if (needsNoResponse(status)) {
return state();
}
using namespace GpgSetOwnerTrustEditInteractor_Private;
switch (state()) {

View File

@ -25,8 +25,8 @@
#ifndef __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
#define __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
#include "editinteractor.h"
#include "key.h"
#include <editinteractor.h>
#include <key.h>
#include <string>

View File

@ -64,13 +64,6 @@ public:
std::vector<unsigned int> userIDs;
std::vector<unsigned int>::const_iterator currentId, nextId;
unsigned int checkLevel;
bool dupeOk;
Key key;
struct {
TrustSignatureTrust trust;
std::string depth;
std::string scope;
} trustSignature;
const char *command() const
{
@ -133,9 +126,7 @@ GpgSignKeyEditInteractor::Private::Private()
userIDs(),
currentId(),
nextId(),
checkLevel(0),
dupeOk(false),
trustSignature{TrustSignatureTrust::None, "0", {}}
checkLevel(0)
{
}
@ -168,9 +159,6 @@ enum SignKeyState {
SET_TRUST_REGEXP,
CONFIRM,
CONFIRM2,
DUPE_OK,
DUPE_OK2,
REJECT_SIGN_EXPIRED,
QUIT,
SAVE,
ERROR = EditInteractor::ErrorState
@ -194,43 +182,30 @@ static GpgSignKeyEditInteractor_Private::TransitionMap makeTable()
#define addEntry( s1, status, str, s2 ) tab[std::make_tuple( s1, status, str)] = s2
addEntry(START, GET_LINE, "keyedit.prompt", COMMAND);
addEntry(COMMAND, GET_BOOL, "keyedit.sign_all.okay", UIDS_ANSWER_SIGN_ALL);
addEntry(COMMAND, GET_BOOL, "sign_uid.expired_okay", REJECT_SIGN_EXPIRED);
addEntry(COMMAND, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(COMMAND, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM2);
addEntry(COMMAND, GET_BOOL, "sign_uid.dupe_okay", DUPE_OK);
addEntry(COMMAND, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(UIDS_ANSWER_SIGN_ALL, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(UIDS_ANSWER_SIGN_ALL, GET_BOOL, "sign_uid.dupe_okay", DUPE_OK);
addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.expire", SET_EXPIRE);
addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(SET_TRUST_VALUE, GET_LINE, "trustsig_prompt.trust_depth", SET_TRUST_DEPTH);
addEntry(SET_TRUST_DEPTH, GET_LINE, "trustsig_prompt.trust_regexp", SET_TRUST_REGEXP);
addEntry(SET_TRUST_REGEXP, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(SET_TRUST_VALUE, GET_LINE, "trustsign_prompt.trust_depth", SET_TRUST_DEPTH);
addEntry(SET_TRUST_DEPTH, GET_LINE, "trustsign_prompt.trust_regexp", SET_TRUST_REGEXP);
addEntry(SET_TRUST_REGEXP, GET_LINE, "sign_uid.okay", CONFIRM);
addEntry(SET_CHECK_LEVEL, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(SET_EXPIRE, GET_BOOL, "sign_uid.class", SET_CHECK_LEVEL);
addEntry(CONFIRM, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
addEntry(DUPE_OK, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(DUPE_OK2, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(DUPE_OK, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(DUPE_OK2, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(CONFIRM, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(CONFIRM2, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(CONFIRM, GET_LINE, "keyedit.prompt", COMMAND);
addEntry(CONFIRM, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(CONFIRM, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
addEntry(CONFIRM, GET_LINE, "sign_uid.expire", SET_EXPIRE);
addEntry(CONFIRM, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "keyedit.prompt", COMMAND);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "trustsig_prompt.trust_value", SET_TRUST_VALUE);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.expire", SET_EXPIRE);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.okay", CONFIRM);
addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.dupe_okay", DUPE_OK);
addEntry(DUPE_OK, GET_BOOL, "sign_uid.dupe_okay", DUPE_OK2);
addEntry(DUPE_OK2, GET_BOOL, "sign_uid.dupe_okay", DUPE_OK);
addEntry(CONFIRM, GET_LINE, "keyedit.prompt", QUIT);
addEntry(REJECT_SIGN_EXPIRED, GET_LINE, "keyedit.prompt", QUIT);
addEntry(ERROR, GET_LINE, "keyedit.prompt", QUIT);
addEntry(QUIT, GET_BOOL, "keyedit.save.okay", SAVE);
#undef addEntry
@ -253,22 +228,17 @@ const char *GpgSignKeyEditInteractor::action(Error &err) const
case SET_EXPIRE:
return answer(true);
case SET_TRUST_VALUE:
return d->trustSignature.trust == TrustSignatureTrust::Partial ? "1" : "2";
// TODO
case SET_TRUST_DEPTH:
return d->trustSignature.depth.c_str();
//TODO
case SET_TRUST_REGEXP:
return d->trustSignature.scope.c_str();
//TODO
return nullptr;
case SET_CHECK_LEVEL:
return check_level_strings[d->checkLevel];
case DUPE_OK:
case DUPE_OK2:
return answer(d->dupeOk);
case CONFIRM2:
case CONFIRM:
return answer(true);
case REJECT_SIGN_EXPIRED:
err = Error::fromCode(GPG_ERR_KEY_EXPIRED);
return answer(false);
case QUIT:
return "quit";
case SAVE:
@ -276,17 +246,7 @@ const char *GpgSignKeyEditInteractor::action(Error &err) const
default:
if (st >= UIDS_LIST_SEPARATELY && st < UIDS_LIST_SEPARATELY_DONE) {
std::stringstream ss;
auto nextID = d->nextUserID();
const char *hash;
assert (nextID);
if (!d->key.isNull() && (hash = d->key.userID(nextID - 1).uidhash())) {
/* Prefer uidhash if it is available as it might happen
* that uidattrs break the ordering of the uids in the
* edit-key interface */
ss << "uid " << hash;
} else {
ss << nextID;
}
ss << d->nextUserID();
d->scratch = ss.str();
return d->scratch.c_str();
}
@ -304,6 +264,9 @@ unsigned int GpgSignKeyEditInteractor::nextState(unsigned int status, const char
static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
//static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
static const TransitionMap table(makeTable());
if (needsNoResponse(status)) {
return state();
}
using namespace GpgSignKeyEditInteractor_Private;
@ -342,10 +305,6 @@ unsigned int GpgSignKeyEditInteractor::nextState(unsigned int status, const char
err = GENERAL_ERROR;
return ERROR;
}
void GpgSignKeyEditInteractor::setKey(const Key &key)
{
d->key = key;
}
void GpgSignKeyEditInteractor::setCheckLevel(unsigned int checkLevel)
{
@ -367,29 +326,3 @@ void GpgSignKeyEditInteractor::setSigningOptions(int options)
assert(!d->started);
d->options = options;
}
void GpgSignKeyEditInteractor::setDupeOk(bool value)
{
assert(!d->started);
d->dupeOk = value;
}
void GpgSignKeyEditInteractor::setTrustSignatureTrust(GpgME::TrustSignatureTrust trust)
{
assert(!d->started);
assert(trust != TrustSignatureTrust::None);
d->trustSignature.trust = trust;
}
void GpgSignKeyEditInteractor::setTrustSignatureDepth(unsigned short depth)
{
assert(!d->started);
assert(depth <= 255);
d->trustSignature.depth = std::to_string(depth);
}
void GpgSignKeyEditInteractor::setTrustSignatureScope(const std::string &scope)
{
assert(!d->started);
d->trustSignature.scope = scope;
}

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
#define __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
#include "editinteractor.h"
#include <editinteractor.h>
#include <string>
#include <vector>
@ -35,7 +35,6 @@ namespace GpgME
class Key;
class UserID;
enum class TrustSignatureTrust : char;
class GPGMEPP_EXPORT GpgSignKeyEditInteractor : public EditInteractor
{
@ -51,18 +50,8 @@ public:
void setCheckLevel(unsigned int checkLevel);
void setUserIDsToSign(const std::vector<unsigned int> &userIDsToSign);
void setKey(const Key &key);
void setSigningOptions(int options);
/* Set this if it is ok to overwrite an existing signature. In that
* case the context has to have the flag "extended-edit" set to 1 through
* Context::setFlag before calling edit.*/
void setDupeOk(bool value);
void setTrustSignatureTrust(TrustSignatureTrust trust);
void setTrustSignatureDepth(unsigned short depth);
void setTrustSignatureScope(const std::string &scope);
private:
const char *action(Error &err) const override;
unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const override;

View File

@ -35,9 +35,6 @@
#include <cstring>
#include <string.h>
#include <strings.h>
#include <istream>
#include <iterator>
class GpgME::ImportResult::Private
{
@ -48,9 +45,7 @@ public:
// We just need to handle the pointers in the structs:
for (gpgme_import_status_t is = r.imports ; is ; is = is->next) {
gpgme_import_status_t copy = new _gpgme_import_status(*is);
if (is->fpr) {
copy->fpr = strdup(is->fpr);
}
copy->fpr = strdup(is->fpr);
copy->next = nullptr;
imports.push_back(copy);
}
@ -94,131 +89,6 @@ void GpgME::ImportResult::init(gpgme_ctx_t ctx)
make_standard_stuff(ImportResult)
void GpgME::ImportResult::mergeWith(const ImportResult &other)
{
if (other.isNull()) {
return;
}
if (isNull()) { // just assign
operator=(other);
return;
}
// Add the numbers of considered keys; the number will be corrected when
// merging the imports to account for duplicates
d->res.considered += other.d->res.considered;
// Add the numbers of keys without user ID; may count duplicates
d->res.no_user_id += other.d->res.no_user_id;
// Add the numbers of imported keys
d->res.imported += other.d->res.imported;
// Add the numbers of imported RSA keys
d->res.imported_rsa += other.d->res.imported_rsa;
// Add the numbers of unchanged keys; the number will be corrected when
// merging the imports to account for keys changed by this import
d->res.unchanged += other.d->res.unchanged;
// Add the numbers of new user IDs
d->res.new_user_ids += other.d->res.new_user_ids;
// Add the numbers of new subkeys
d->res.new_sub_keys += other.d->res.new_sub_keys;
// Add the numbers of new signatures
d->res.new_signatures += other.d->res.new_signatures;
// Add the numbers of new revocations
d->res.new_revocations += other.d->res.new_revocations;
// Add the numbers of considered secret keys; the number will be corrected when
// merging the imports to account for duplicates
d->res.secret_read += other.d->res.secret_read;
// Add the numbers of imported secret keys
d->res.secret_imported += other.d->res.secret_imported;
// Add the numbers of unchanged secret keys; the number will be corrected when
// merging the imports to account for keys changed by this import
d->res.secret_unchanged += other.d->res.secret_unchanged;
// Add the numbers of new keys that were skipped; may count duplicates
d->res.skipped_new_keys += other.d->res.skipped_new_keys;
// Add the numbers of keys that were not imported; may count duplicates
d->res.not_imported += other.d->res.not_imported;
// Add the numbers of v3 keys that were skipped; may count duplicates
d->res.skipped_v3_keys += other.d->res.skipped_v3_keys;
// Look at the list of keys for which an import was attempted during the
// other import to correct some of the consolidated numbers
for (auto it = std::begin(other.d->imports), end = std::end(other.d->imports); it != end; ++it) {
const char *fpr = (*it)->fpr;
if (!fpr || !*fpr) {
// we cannot derive any useful information about an import if the
// fingerprint is null or empty
continue;
}
// was this key also considered during the first import
const auto consideredInFirstImports =
std::any_of(std::begin(d->imports), std::end(d->imports), [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr);
});
// did we see this key already in the list of keys of the other import
const auto consideredInPreviousOtherImports =
std::any_of(std::begin(other.d->imports), it, [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr);
});
// was anything added to this key during the other import
const auto changedInOtherImports =
std::any_of(std::begin(other.d->imports), std::end(other.d->imports), [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr) && (i->status != 0);
});
if (consideredInFirstImports && !consideredInPreviousOtherImports) {
// key was also considered during first import, but not before in the list of other imports
d->res.considered -= 1;
if (!changedInOtherImports) {
// key was (most likely) counted as unchanged in the second import;
// this needs to be corrected (regardless of whether it was changed in the first import)
d->res.unchanged -= 1;
}
}
// now do the same for the secret key counts
const auto secretKeyConsideredInFirstImports =
std::any_of(std::begin(d->imports), std::end(d->imports), [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr) && (i->status & GPGME_IMPORT_SECRET);
});
const auto secretKeyConsideredInPreviousOtherImports =
std::any_of(std::begin(other.d->imports), it, [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr) && (i->status & GPGME_IMPORT_SECRET);
});
const auto secretKeyChangedInOtherImports =
std::any_of(std::begin(other.d->imports), std::end(other.d->imports), [fpr](const gpgme_import_status_t i) {
return i->fpr && !strcmp(i->fpr, fpr) && (i->status & GPGME_IMPORT_SECRET) && (i->status != GPGME_IMPORT_SECRET);
});
if (secretKeyConsideredInFirstImports && !secretKeyConsideredInPreviousOtherImports) {
// key was also considered during first import, but not before in the list of other imports
d->res.secret_read -= 1;
if (!secretKeyChangedInOtherImports) {
// key was (most likely) counted as unchanged in the second import;
// this needs to be corrected (regardless of whether it was changed in the first import)
d->res.secret_unchanged -= 1;
}
}
}
// Now append the list of keys for which an import was attempted during the
// other import
d->imports.reserve(d->imports.size() + other.d->imports.size());
std::transform(std::begin(other.d->imports), std::end(other.d->imports),
std::back_inserter(d->imports),
[](const gpgme_import_status_t import) {
gpgme_import_status_t copy = new _gpgme_import_status{*import};
if (import->fpr) {
copy->fpr = strdup(import->fpr);
}
copy->next = nullptr; // should already be null, but better safe than sorry
return copy;
});
// Finally, merge the error if there was none yet
if (!bool(error())) {
Result::operator=(other);
}
}
int GpgME::ImportResult::numConsidered() const
{
return d ? d->res.considered : 0 ;
@ -354,42 +224,3 @@ GpgME::Import::Status GpgME::Import::status() const
}
return static_cast<Status>(result);
}
std::ostream &GpgME::operator<<(std::ostream &os,
const GpgME::ImportResult &result)
{
os << "GpgME::ImportResult(";
if (!result.isNull()) {
os << "\n considered: " << result.numConsidered()
<< "\n without UID: " << result.numKeysWithoutUserID()
<< "\n imported: " << result.numImported()
<< "\n RSA Imported: " << result.numRSAImported()
<< "\n unchanged: " << result.numUnchanged()
<< "\n newUserIDs: " << result.newUserIDs()
<< "\n newSubkeys: " << result.newSubkeys()
<< "\n newSignatures: " << result.newSignatures()
<< "\n newRevocations: " << result.newRevocations()
<< "\n numSecretKeysConsidered: " << result.numSecretKeysConsidered()
<< "\n numSecretKeysImported: " << result.numSecretKeysImported()
<< "\n numSecretKeysUnchanged: " << result.numSecretKeysUnchanged()
<< "\n"
<< "\n notImported: " << result.notImported()
<< "\n numV3KeysSkipped: " << result.numV3KeysSkipped()
<< "\n imports:\n";
const std::vector<Import> imp = result.imports();
std::copy(imp.begin(), imp.end(),
std::ostream_iterator<Import>(os, "\n"));
}
return os << ')';
}
std::ostream &GpgME::operator<<(std::ostream &os, const GpgME::Import &imp)
{
os << "GpgME::Import(";
if (!imp.isNull()) {
os << "\n fpr: " << (imp.fingerprint() ? imp.fingerprint() : "null")
<< "\n status: " << imp.status()
<< "\n err: " << imp.error();
}
return os << ')';
}

View File

@ -47,7 +47,6 @@ public:
ImportResult(gpgme_ctx_t ctx, const Error &error);
explicit ImportResult(const Error &error);
ImportResult(const ImportResult &other) = default;
const ImportResult &operator=(ImportResult other)
{
swap(other);
@ -61,16 +60,6 @@ public:
swap(this->d, other.d);
}
/**
* Merges the result @p other into this result (and all of its copies).
*
* @note The merge algorithm assumes that @p other is the result of an
* import that was performed after the import of this result.
* @note Some numbers cannot be consolidated reliably, e.g. the number of
* keys without user ID.
*/
void mergeWith(const ImportResult &other);
bool isNull() const;
int numConsidered() const;
@ -107,7 +96,6 @@ class GPGMEPP_EXPORT Import
public:
Import();
Import(const Import &other) = default;
const Import &operator=(Import other)
{
swap(other);
@ -141,10 +129,7 @@ private:
unsigned int idx;
};
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const ImportResult &irs);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Import &imp);
} // namespace GpgME
}
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(ImportResult)
GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Import)

View File

@ -26,7 +26,7 @@
#ifndef __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
#define __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
#include "../gpgmepp_export.h"
#include "gpgmepp_export.h"
#include <stddef.h>

View File

@ -27,7 +27,7 @@
#include <sys/types.h>
#include "../gpgmepp_export.h"
#include "gpgmepp_export.h"
#include <gpg-error.h>

View File

@ -29,13 +29,11 @@
#include "util.h"
#include "tofuinfo.h"
#include "context.h"
#include "engineinfo.h"
#include <gpgme.h>
#include <string.h>
#include <strings.h>
#include <cassert>
#include <istream>
#include <iterator>
@ -122,37 +120,6 @@ std::vector<Subkey> Key::subkeys() const
return v;
}
RevocationKey Key::revocationKey(unsigned int index) const
{
return RevocationKey(key, index);
}
unsigned int Key::numRevocationKeys() const
{
if (!key) {
return 0;
}
unsigned int count = 0;
for (auto revkey = key->revocation_keys; revkey; revkey = revkey->next) {
++count;
}
return count;
}
std::vector<RevocationKey> Key::revocationKeys() const
{
if (!key) {
return std::vector<RevocationKey>();
}
std::vector<RevocationKey> v;
v.reserve(numRevocationKeys());
for (auto revkey = key->revocation_keys; revkey; revkey = revkey->next) {
v.push_back(RevocationKey(key, revkey));
}
return v;
}
Key::OwnerTrust Key::ownerTrust() const
{
if (!key) {
@ -239,12 +206,17 @@ bool Key::canEncrypt() const
bool Key::canSign() const
{
return key && key->can_sign;
#ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
return true;
}
#endif
return canReallySign();
}
bool Key::canReallySign() const
{
return canSign();
return key && key->can_sign;
}
bool Key::canCertify() const
@ -278,26 +250,6 @@ bool Key::isDeVs() const
return true;
}
bool Key::hasCertify() const
{
return key && key->has_certify;
}
bool Key::hasSign() const
{
return key && key->has_sign;
}
bool Key::hasEncrypt() const
{
return key && key->has_encrypt;
}
bool Key::hasAuthenticate() const
{
return key && key->has_authenticate;
}
const char *Key::issuerSerial() const
{
return key ? key->issuer_serial : nullptr ;
@ -385,10 +337,6 @@ const Key &Key::mergeWith(const Key &other)
for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
if (strcmp(mysk->fpr, hissk->fpr) == 0) {
mysk->is_cardkey |= hissk->is_cardkey;
mysk->secret |= hissk->secret;
if (hissk->keygrip && !mysk->keygrip) {
mysk->keygrip = strdup(hissk->keygrip);
}
break;
}
}
@ -410,25 +358,20 @@ void Key::update()
KeyListMode::Signatures |
KeyListMode::SignatureNotations |
KeyListMode::Validate |
KeyListMode::WithTofu |
KeyListMode::WithKeygrip |
KeyListMode::WithSecret);
KeyListMode::WithTofu);
Error err;
Key newKey;
if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.0") {
newKey = ctx->key(primaryFingerprint(), err, true);
// Not secret so we get the information from the pubring.
if (newKey.isNull()) {
newKey = ctx->key(primaryFingerprint(), err, false);
}
} else {
auto newKey = ctx->key(primaryFingerprint(), err, true);
// Not secret so we get the information from the pubring.
if (newKey.isNull())
{
newKey = ctx->key(primaryFingerprint(), err, false);
}
}
delete ctx;
if (err) {
return;
}
swap(newKey);
return;
}
// static
@ -458,7 +401,7 @@ Key Key::locate(const char *mbox)
//
//
static gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
{
if (key) {
for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
@ -470,7 +413,7 @@ static gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int i
return nullptr;
}
static gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
{
if (key) {
for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
@ -561,21 +504,6 @@ bool Subkey::canAuthenticate() const
return subkey && subkey->can_authenticate;
}
bool Subkey::canRenc() const
{
return subkey && subkey->can_renc;
}
bool Subkey::canTimestamp() const
{
return subkey && subkey->can_timestamp;
}
bool Subkey::isGroupOwned() const
{
return subkey && subkey->is_group_owned;
}
bool Subkey::isQualified() const
{
return subkey && subkey->is_qualified;
@ -652,7 +580,7 @@ bool Subkey::isDisabled() const
//
//
static gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
{
if (key) {
for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
@ -664,7 +592,7 @@ static gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
return nullptr;
}
static gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
{
if (key) {
for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
@ -746,11 +674,6 @@ const char *UserID::comment() const
return uid ? uid->comment : nullptr ;
}
const char *UserID::uidhash() const
{
return uid ? uid->uidhash : nullptr ;
}
UserID::Validity UserID::validity() const
{
if (!uid) {
@ -801,83 +724,13 @@ TofuInfo UserID::tofuInfo() const
return TofuInfo(uid->tofu);
}
static gpgme_key_sig_t find_last_valid_sig_for_keyid (gpgme_user_id_t uid,
const char *keyid)
{
if (!keyid) {
return nullptr;
}
gpgme_key_sig_t ret = NULL;
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
if (s->keyid && !strcmp(keyid, s->keyid)) {
if (!s->expired && !s->revoked && !s->invalid && !s->status) {
if (!ret) {
ret = s;
} else if (ret && ret->timestamp <= s->timestamp) {
/* Equals because when the timestamps are the same we prefer
the last in the list */
ret = s;
}
}
}
}
return ret;
}
const char *UserID::remark(const Key &remarker, Error &err) const
{
if (!uid || remarker.isNull()) {
err = Error::fromCode(GPG_ERR_GENERAL);
return nullptr;
}
if (key->protocol != GPGME_PROTOCOL_OpenPGP) {
return nullptr;
}
if (!(key->keylist_mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) ||
!(key->keylist_mode & GPGME_KEYLIST_MODE_SIGS)) {
err = Error::fromCode(GPG_ERR_NO_DATA);
return nullptr;
}
gpgme_key_sig_t s = find_last_valid_sig_for_keyid(uid, remarker.keyID());
if (!s) {
return nullptr;
}
for (gpgme_sig_notation_t n = s->notations; n ; n = n->next) {
if (n->name && !strcmp(n->name, "rem@gnupg.org")) {
return n->value;
}
}
return nullptr;
}
std::vector<std::string> UserID::remarks(std::vector<Key> keys, Error &err) const
{
std::vector<std::string> ret;
for (const auto &key: keys) {
const char *rem = remark(key, err);
if (err) {
return ret;
}
if (rem) {
ret.push_back(rem);
}
}
return ret;
}
//
//
// class Signature
//
//
static gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
{
if (uid) {
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
@ -889,7 +742,7 @@ static gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
return nullptr;
}
static gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
{
if (uid) {
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
@ -901,82 +754,18 @@ static gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig
return nullptr;
}
static int signature_index(gpgme_user_id_t uid, gpgme_key_sig_t sig)
{
if (uid) {
int i = 0;
for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, ++i) {
if (s == sig) {
return i;
}
}
}
return -1;
}
UserID::Signature::Signature() : key(), uid(nullptr), sig(nullptr) {}
UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
: key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
{
}
UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
: key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
{
}
bool UserID::Signature::operator<(const Signature &other)
{
// kept for binary compatibility
return static_cast<const UserID::Signature *>(this)->operator<(other);
}
bool UserID::Signature::operator<(const Signature &other) const
{
// based on cmp_signodes() in g10/keylist.c
// both signatures must belong to the same user ID
assert(uid == other.uid);
// self-signatures are ordered first
const char *primaryKeyId = parent().parent().keyID();
const bool thisIsSelfSignature = strcmp(signerKeyID(), primaryKeyId) == 0;
const bool otherIsSelfSignature = strcmp(other.signerKeyID(), primaryKeyId) == 0;
if (thisIsSelfSignature && !otherIsSelfSignature) {
return true;
}
if (otherIsSelfSignature && !thisIsSelfSignature) {
return false;
}
// then sort by signer key ID (which are or course the same for self-sigs)
const int keyIdComparison = strcmp(signerKeyID(), other.signerKeyID());
if (keyIdComparison < 0) {
return true;
}
if (keyIdComparison > 0) {
return false;
}
// followed by creation time
if (creationTime() < other.creationTime()) {
return true;
}
if (creationTime() > other.creationTime()) {
return false;
}
// followed by the class in a way that a rev comes first
if (certClass() < other.certClass()) {
return true;
}
if (certClass() > other.certClass()) {
return false;
}
// to make the sort stable we compare the indexes of the signatures as last resort
return signature_index(uid, sig) < signature_index(uid, other.sig);
}
UserID UserID::Signature::parent() const
@ -1144,29 +933,6 @@ const char *UserID::Signature::policyURL() const
return nullptr;
}
bool UserID::Signature::isTrustSignature() const
{
return sig && sig->trust_depth > 0;
}
TrustSignatureTrust UserID::Signature::trustValue() const
{
if (!sig || !isTrustSignature()) {
return TrustSignatureTrust::None;
}
return sig->trust_value >= 120 ? TrustSignatureTrust::Complete : TrustSignatureTrust::Partial;
}
unsigned int UserID::Signature::trustDepth() const
{
return sig ? sig->trust_depth : 0;
}
const char *UserID::Signature::trustScope() const
{
return sig ? sig->trust_scope : nullptr;
}
std::string UserID::addrSpecFromString(const char *userid)
{
if (!userid) {
@ -1287,68 +1053,6 @@ bool UserID::Signature::isBad() const
return isNull() || isExpired() || isInvalid();
}
//
//
// class RevocationKey
//
//
static gpgme_revocation_key_t find_revkey(const shared_gpgme_key_t &key, unsigned int idx)
{
if (key) {
for (gpgme_revocation_key_t s = key->revocation_keys; s; s = s->next, --idx) {
if (idx == 0) {
return s;
}
}
}
return nullptr;
}
static gpgme_revocation_key_t verify_revkey(const shared_gpgme_key_t &key, gpgme_revocation_key_t revkey)
{
if (key) {
for (gpgme_revocation_key_t s = key->revocation_keys; s; s = s->next) {
if (s == revkey) {
return revkey;
}
}
}
return nullptr;
}
RevocationKey::RevocationKey() : key(), revkey(nullptr) {}
RevocationKey::RevocationKey(const shared_gpgme_key_t &k, unsigned int idx)
: key(k), revkey(find_revkey(k, idx))
{
}
RevocationKey::RevocationKey(const shared_gpgme_key_t &k, gpgme_revocation_key_t sk)
: key(k), revkey(verify_revkey(k, sk))
{
}
Key RevocationKey::parent() const
{
return Key(key);
}
const char *RevocationKey::fingerprint() const
{
return revkey ? revkey->fpr : nullptr;
}
bool RevocationKey::isSensitive() const
{
return revkey ? revkey->sensitive : false;
}
int RevocationKey::algorithm() const
{
return revkey ? revkey->pubkey_algo : 0;
}
std::ostream &operator<<(std::ostream &os, const UserID &uid)
{
os << "GpgME::UserID(";
@ -1368,34 +1072,6 @@ std::ostream &operator<<(std::ostream &os, const UserID &uid)
return os << ')';
}
std::ostream &operator<<(std::ostream &os, const Subkey &subkey)
{
os << "GpgME::Subkey(";
if (!subkey.isNull()) {
os << "\n fingerprint: " << protect(subkey.fingerprint())
<< "\n keyGrip: " << protect(subkey.keyGrip())
<< "\n creationTime: " << subkey.creationTime()
<< "\n expirationTime:" << subkey.expirationTime()
<< "\n isRevoked: " << subkey.isRevoked()
<< "\n isExpired: " << subkey.isExpired()
<< "\n isInvalid: " << subkey.isInvalid()
<< "\n isDisabled: " << subkey.isDisabled()
<< "\n canSign: " << subkey.canSign()
<< "\n canEncrypt: " << subkey.canEncrypt()
<< "\n canCertify: " << subkey.canCertify()
<< "\n canAuth: " << subkey.canAuthenticate()
<< "\n canRenc: " << subkey.canRenc()
<< "\n canTimestanp: " << subkey.canTimestamp()
<< "\n isSecret: " << subkey.isSecret()
<< "\n isGroupOwned: " << subkey.isGroupOwned()
<< "\n isQualified: " << subkey.isQualified()
<< "\n isDeVs: " << subkey.isDeVs()
<< "\n isCardKey: " << subkey.isCardKey()
<< "\n cardSerialNumber:" << protect(subkey.cardSerialNumber());
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, const Key &key)
{
os << "GpgME::Key(";
@ -1405,7 +1081,7 @@ std::ostream &operator<<(std::ostream &os, const Key &key)
<< "\n issuer: " << protect(key.issuerName())
<< "\n fingerprint:" << protect(key.primaryFingerprint())
<< "\n listmode: " << key.keyListMode()
<< "\n canSign: " << key.canSign()
<< "\n canSign: " << key.canReallySign()
<< "\n canEncrypt: " << key.canEncrypt()
<< "\n canCertify: " << key.canCertify()
<< "\n canAuth: " << key.canAuthenticate()
@ -1415,23 +1091,6 @@ std::ostream &operator<<(std::ostream &os, const Key &key)
const std::vector<UserID> uids = key.userIDs();
std::copy(uids.begin(), uids.end(),
std::ostream_iterator<UserID>(os, "\n"));
const std::vector<Subkey> subkeys = key.subkeys();
std::copy(subkeys.begin(), subkeys.end(),
std::ostream_iterator<Subkey>(os, "\n"));
os << " revocationKeys:\n";
const std::vector<RevocationKey> revkeys = key.revocationKeys();
std::copy(revkeys.begin(), revkeys.end(),
std::ostream_iterator<RevocationKey>(os, "\n"));
}
return os << ')';
}
std::ostream &operator<<(std::ostream &os, const RevocationKey &revkey)
{
os << "GpgME::RevocationKey(";
if (!revkey.isNull()) {
os << "\n fingerprint: " << protect(revkey.fingerprint())
<< "\n isSensitive: " << revkey.isSensitive();
}
return os << ')';
}

View File

@ -44,16 +44,9 @@ class Context;
class Subkey;
class UserID;
class TofuInfo;
class RevocationKey;
typedef std::shared_ptr< std::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
enum class TrustSignatureTrust : char {
None = 0,
Partial,
Complete,
};
//
// class Key
//
@ -72,7 +65,6 @@ public:
static const Null null;
Key(const Key &other) = default;
const Key &operator=(Key other)
{
swap(other);
@ -101,10 +93,6 @@ public:
std::vector<UserID> userIDs() const;
std::vector<Subkey> subkeys() const;
RevocationKey revocationKey(unsigned int index) const;
unsigned int numRevocationKeys() const;
std::vector<RevocationKey> revocationKeys() const;
bool isRevoked() const;
bool isExpired() const;
bool isDisabled() const;
@ -114,31 +102,22 @@ public:
* isDisabled || isInvalid */
bool isBad() const;
/** Returns true, if the key can be used for encryption (i.e. it's not bad
* and has an encryption subkey) or if the primary subkey can encrypt. */
bool canEncrypt() const;
/** Returns true, if the key can be used for signing (i.e. it's not bad
* and has a signing subkey) or if the primary subkey can sign. */
/*!
This function contains a workaround for old gpgme's: all secret
OpenPGP keys canSign() == true, which canReallySign() doesn't
have. I don't have time to find what breaks when I remove this
workaround, but since Kleopatra merges secret into public keys,
the workaround is not necessary there (and actively harms), I've
added a new function instead.
*/
bool canSign() const;
GPGMEPP_DEPRECATED bool canReallySign() const;
/** Returns true, if the key can be used for certification (i.e. it's not bad
* and has a certification subkey) or if the primary subkey can certify. */
bool canReallySign() const;
bool canCertify() const;
/** Returns true, if the key can be used for authentication (i.e. it's not bad
* and has a authentication subkey) or if the primary subkey can authenticate. */
bool canAuthenticate() const;
bool isQualified() const;
bool isDeVs() const;
/** Returns true, if the key has a certification subkey. */
bool hasCertify() const;
/** Returns true, if the key has a signing subkey. */
bool hasSign() const;
/** Returns true, if the key has an encryption subkey. */
bool hasEncrypt() const;
/** Returns true, if the key has an authentication subkey. */
bool hasAuthenticate() const;
bool hasSecret() const;
GPGMEPP_DEPRECATED bool isSecret() const
{
@ -243,7 +222,6 @@ public:
Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
Subkey(const shared_gpgme_key_t &key, unsigned int idx);
Subkey(const Subkey &other) = default;
const Subkey &operator=(Subkey other)
{
swap(other);
@ -284,9 +262,6 @@ public:
bool canSign() const;
bool canCertify() const;
bool canAuthenticate() const;
bool canRenc() const;
bool canTimestamp() const;
bool isGroupOwned() const;
bool isQualified() const;
bool isDeVs() const;
bool isCardKey() const;
@ -360,7 +335,6 @@ public:
UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
UserID(const shared_gpgme_key_t &key, unsigned int idx);
UserID(const UserID &other) = default;
const UserID &operator=(UserID other)
{
swap(other);
@ -389,7 +363,6 @@ public:
const char *name() const;
const char *email() const;
const char *comment() const;
const char *uidhash() const;
enum Validity { Unknown = 0, Undefined = 1, Never = 2,
Marginal = 3, Full = 4, Ultimate = 5
@ -440,27 +413,6 @@ public:
*
* @returns the last update time. */
time_t lastUpdate() const;
/*! Get a remark made by the key provided.
* A remark is a signature notation on
* this user id made by the key with the
* name "rem@gnupg.org". Returns an error if the
* parent key of this user id was not listed with the
* keylist mode flags for signatures and signature notations.
*
* @param key The key for which comments should be searched.
* @param error Set to GPG_ERR_NO_DATA if the keylist did
* not include signature notations.
*
* @returns The value of the comment or NULL if none exists.
**/
const char *remark(const Key &key,
Error &error) const;
/*! Get multiple remarks made by potentially multiple keys. */
std::vector <std::string> remarks(std::vector<GpgME::Key> remarkers,
Error &error) const;
private:
shared_gpgme_key_t key;
gpgme_user_id_t uid;
@ -479,7 +431,6 @@ public:
Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
Signature(const Signature &other) = default;
const Signature &operator=(Signature other)
{
swap(other);
@ -494,11 +445,6 @@ public:
swap(this->sig, other.sig);
}
/*! Defines a canonical sort order for signatures of the same user ID. */
bool operator<(const Signature &other) const;
GPGMEPP_DEPRECATED bool operator<(const Signature &other);
bool isNull() const
{
return !sig || !uid || !key ;
@ -541,64 +487,14 @@ public:
GpgME::Notation notation(unsigned int idx) const;
std::vector<GpgME::Notation> notations() const;
bool isTrustSignature() const;
TrustSignatureTrust trustValue() const;
unsigned int trustDepth() const;
const char *trustScope() const;
private:
shared_gpgme_key_t key;
gpgme_user_id_t uid;
gpgme_key_sig_t sig;
};
//
// class RevocationKey
//
class GPGMEPP_EXPORT RevocationKey
{
public:
RevocationKey();
RevocationKey(const shared_gpgme_key_t &key, gpgme_revocation_key_t revkey);
RevocationKey(const shared_gpgme_key_t &key, unsigned int idx);
// Rule of Zero
void swap(RevocationKey &other)
{
using std::swap;
swap(this->key, other.key);
swap(this->revkey, other.revkey);
}
bool isNull() const
{
return !key || !revkey;
}
Key parent() const;
const char *fingerprint() const;
bool isSensitive() const;
int algorithm() const;
private:
shared_gpgme_key_t key;
gpgme_revocation_key_t revkey;
};
inline void swap(RevocationKey& v1, RevocationKey& v2)
{
v1.swap(v2);
}
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const UserID &uid);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Subkey &subkey);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Key &key);
GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const RevocationKey &revkey);
} // namespace GpgME

View File

@ -44,7 +44,6 @@ public:
KeyGenerationResult(gpgme_ctx_t ctx, const Error &error);
explicit KeyGenerationResult(const Error &err);
KeyGenerationResult(const KeyGenerationResult &other) = default;
const KeyGenerationResult &operator=(KeyGenerationResult other)
{
swap(other);

View File

@ -45,7 +45,6 @@ public:
explicit KeyListResult(const Error &err);
KeyListResult(const Error &err, const _gpgme_op_keylist_result &res);
KeyListResult(const KeyListResult &other) = default;
const KeyListResult &operator=(KeyListResult other)
{
swap(other);

View File

@ -44,7 +44,6 @@ public:
Notation();
explicit Notation(gpgme_sig_notation_t nota);
Notation(const Notation &other) = default;
const Notation &operator=(Notation other)
{
swap(other);

View File

@ -50,14 +50,6 @@ public:
{
return mError;
}
/**
* Replaces the error set during construction with \p error.
* Use with care, e.g. to set a more suitable error.
*/
void setError(const Error &error)
{
mError = error;
}
protected:
Error mError;

View File

@ -31,6 +31,7 @@
#include "data.h"
#include "util.h"
#include <sstream>
#include <assert.h>
using namespace GpgME;

View File

@ -25,7 +25,7 @@
#ifndef __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
#define __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
#include "interfaces/assuantransaction.h"
#include <interfaces/assuantransaction.h>
#include <string>
#include <vector>

View File

@ -199,8 +199,6 @@ GpgME::SignatureMode GpgME::CreatedSignature::mode() const
case GPGME_SIG_MODE_NORMAL: return NormalSignatureMode;
case GPGME_SIG_MODE_DETACH: return Detached;
case GPGME_SIG_MODE_CLEAR: return Clearsigned;
case GPGME_SIG_MODE_ARCHIVE: return SignArchive; // cannot happen
case GPGME_SIG_MODE_FILE: return SignFile; // cannot happen
}
}

View File

@ -50,7 +50,6 @@ public:
SigningResult(gpgme_ctx_t ctx, const Error &error);
explicit SigningResult(const Error &err);
SigningResult(const SigningResult &other) = default;
const SigningResult &operator=(SigningResult other)
{
swap(other);
@ -87,7 +86,6 @@ class GPGMEPP_EXPORT InvalidSigningKey
public:
InvalidSigningKey();
InvalidSigningKey(const InvalidSigningKey &other) = default;
const InvalidSigningKey &operator=(InvalidSigningKey other)
{
swap(other);
@ -121,7 +119,6 @@ public:
CreatedSignature();
CreatedSignature(const CreatedSignature &other) = default;
const CreatedSignature &operator=(CreatedSignature other)
{
swap(other);

View File

@ -1,67 +0,0 @@
/*
statusconsumerassuantransaction.cpp
Copyright (c) 2020 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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 "statusconsumerassuantransaction.h"
#include "data.h"
#include "error.h"
#include "interfaces/statusconsumer.h"
using namespace GpgME;
StatusConsumerAssuanTransaction::StatusConsumerAssuanTransaction(StatusConsumer *statusConsumer)
: AssuanTransaction()
, m_consumer(statusConsumer)
{
}
StatusConsumerAssuanTransaction::~StatusConsumerAssuanTransaction()
{
}
Error StatusConsumerAssuanTransaction::data(const char *data, size_t datalen)
{
(void) data;
(void) datalen;
return Error();
}
Data StatusConsumerAssuanTransaction::inquire(const char *name, const char *args, Error &err)
{
(void)name;
(void)args;
(void)err;
return Data::null;
}
Error StatusConsumerAssuanTransaction::status(const char *status, const char *args)
{
m_consumer->status(status, args);
return Error();
}

View File

@ -1,51 +0,0 @@
/*
statusconsumerassuantransaction.h - Assuan transaction that forwards status lines to a consumer
Copyright (c) 2020 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
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.
*/
#ifndef __GPGMEPP_STATUSCONSUMERASSUANTRANSACTION_H__
#define __GPGMEPP_STATUSCONSUMERASSUANTRANSACTION_H__
#include "interfaces/assuantransaction.h"
namespace GpgME
{
class StatusConsumer;
class GPGMEPP_EXPORT StatusConsumerAssuanTransaction: public AssuanTransaction
{
public:
explicit StatusConsumerAssuanTransaction(StatusConsumer *statusConsumer);
~StatusConsumerAssuanTransaction();
private:
Error data(const char *data, size_t datalen) override;
Data inquire(const char *name, const char *args, Error &err) override;
Error status(const char *status, const char *args) override;
private:
StatusConsumer *m_consumer;
};
} // namespace GpgME
#endif // __GPGMEPP_STATUSCONSUMERASSUANTRANSACTION_H__

View File

@ -62,7 +62,6 @@ public:
const char *iversion = NULL,
Error *err = NULL);
SwdbResult(const SwdbResult &other) = default;
const SwdbResult &operator=(SwdbResult other)
{
swap(other);

View File

@ -39,7 +39,6 @@ public:
TofuInfo();
explicit TofuInfo(gpgme_tofu_info_t info);
TofuInfo(const TofuInfo &other) = default;
const TofuInfo &operator=(TofuInfo other)
{
swap(other);

View File

@ -27,7 +27,7 @@
#define __GPGMEPP_TRUSTITEM_H__
#include "gpgmefw.h"
#include "key.h"
#include <key.h>
#include "gpgmepp_export.h"
#include <algorithm>

View File

@ -1,10 +1,8 @@
/*
util.h - some internal helpers
util.h - some inline helper functions
Copyright (C) 2004 Klarälvdalens Datakonsult AB
2016 Bundesamt für Sicherheit in der Informationstechnik
Software engineering by Intevation GmbH
Copyright (c) 2022 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
This file is part of GPGME++.
@ -74,30 +72,19 @@ static inline gpgme_keylist_mode_t add_to_gpgme_keylist_mode_t(unsigned int oldm
if (newmodes & GpgME::SignatureNotations) {
oldmode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
}
if (newmodes & GpgME::Validate) {
oldmode |= GPGME_KEYLIST_MODE_VALIDATE;
}
if (newmodes & GpgME::Ephemeral) {
oldmode |= GPGME_KEYLIST_MODE_EPHEMERAL;
}
if (newmodes & GpgME::Validate) {
oldmode |= GPGME_KEYLIST_MODE_VALIDATE;
}
if (newmodes & GpgME::WithTofu) {
oldmode |= GPGME_KEYLIST_MODE_WITH_TOFU;
}
if (newmodes & GpgME::WithKeygrip) {
oldmode |= GPGME_KEYLIST_MODE_WITH_KEYGRIP;
}
if (newmodes & GpgME::WithSecret) {
oldmode |= GPGME_KEYLIST_MODE_WITH_SECRET;
}
if (newmodes & GpgME::ForceExtern) {
oldmode |= GPGME_KEYLIST_MODE_FORCE_EXTERN;
}
#ifndef NDEBUG
if (newmodes & ~(GpgME::KeyListModeMask)) {
if (newmodes & ~(GpgME::Local | GpgME::Extern | GpgME::Signatures | GpgME::SignatureNotations | GpgME::Ephemeral | GpgME::Validate)) {
//std::cerr << "GpgME::Context: keylist mode must be one of Local, "
//"Extern, Signatures, SignatureNotations, Validate, Ephemeral, WithTofu, "
//"WithKeygrip, WithSecret, ForceExtern, or a combination thereof!"
//<< std::endl;
//"Extern, Signatures, SignatureNotations, or Validate, or a combination thereof!" << std::endl;
}
#endif
return static_cast<gpgme_keylist_mode_t>(oldmode);
@ -118,35 +105,19 @@ static inline unsigned int convert_from_gpgme_keylist_mode_t(unsigned int mode)
if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) {
result |= GpgME::SignatureNotations;
}
if (mode & GPGME_KEYLIST_MODE_WITH_SECRET) {
result |= GpgME::WithSecret;
}
if (mode & GPGME_KEYLIST_MODE_WITH_TOFU) {
result |= GpgME::WithTofu;
}
if (mode & GPGME_KEYLIST_MODE_WITH_KEYGRIP) {
result |= GpgME::WithKeygrip;
}
if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) {
result |= GpgME::Ephemeral;
}
if (mode & GPGME_KEYLIST_MODE_VALIDATE) {
result |= GpgME::Validate;
}
if (mode & GPGME_KEYLIST_MODE_FORCE_EXTERN) {
result |= GpgME::ForceExtern;
}
#ifndef NDEBUG
if (mode & ~(GPGME_KEYLIST_MODE_LOCAL |
GPGME_KEYLIST_MODE_EXTERN |
GPGME_KEYLIST_MODE_SIGS |
GPGME_KEYLIST_MODE_SIG_NOTATIONS |
GPGME_KEYLIST_MODE_WITH_SECRET |
GPGME_KEYLIST_MODE_WITH_TOFU |
GPGME_KEYLIST_MODE_WITH_KEYGRIP |
GPGME_KEYLIST_MODE_EPHEMERAL |
GPGME_KEYLIST_MODE_VALIDATE |
GPGME_KEYLIST_MODE_FORCE_EXTERN)) {
GPGME_KEYLIST_MODE_SIGS)) {
//std::cerr << "GpgME: WARNING: gpgme_get_keylist_mode() returned an unknown flag!" << std::endl;
}
#endif // NDEBUG
@ -177,38 +148,4 @@ static inline gpgme_sig_notation_flags_t add_to_gpgme_sig_notation_flags_t(unsi
return static_cast<gpgme_sig_notation_flags_t>(result);
}
static inline std::vector<std::string> split(const std::string &text, char delimiter)
{
std::vector<std::string> result;
if (!text.empty()) {
std::istringstream stream{text};
std::string line;
while (std::getline(stream, line, delimiter)) {
result.push_back(line);
}
}
return result;
}
/**
* Adapter for passing a vector of strings as NULL-terminated array of
* const char* to the C-interface of gpgme.
*/
class StringsToCStrings
{
public:
explicit StringsToCStrings(const std::vector<std::string> &v);
~StringsToCStrings() = default;
StringsToCStrings(const StringsToCStrings &) = delete;
StringsToCStrings &operator=(const StringsToCStrings &) = delete;
StringsToCStrings(StringsToCStrings &&) = delete;
StringsToCStrings &operator=(StringsToCStrings &&) = delete;
const char **c_strs() const;
private:
const std::vector<std::string> m_strings;
mutable std::vector<const char *> m_cstrings;
};
#endif // __GPGMEPP_UTIL_H__

View File

@ -413,8 +413,7 @@ GpgME::Key GpgME::Signature::key(bool search, bool update) const
KeyListMode::Signatures |
KeyListMode::SignatureNotations |
KeyListMode::Validate |
KeyListMode::WithTofu |
KeyListMode::WithKeygrip);
KeyListMode::WithTofu);
Error e;
ret = d->keys[idx] = ctx->key(fingerprint(), e, false);
delete ctx;
@ -544,41 +543,32 @@ std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &resu
std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus)
{
#define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
os << "GpgME::Signature::PKAStatus(";
switch (pkaStatus) {
#define OUTPUT( x ) case GpgME::Signature:: x: os << #x; break
OUTPUT(UnknownPKAStatus);
OUTPUT(PKAVerificationFailed);
OUTPUT(PKAVerificationSucceeded);
OUTPUT(UnknownPKAStatus);
OUTPUT(PKAVerificationFailed);
OUTPUT(PKAVerificationSucceeded);
#undef OUTPUT
default:
os << "??? (" << static_cast<int>(pkaStatus) << ')';
break;
}
return os << ')';
}
std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary)
{
os << "GpgME::Signature::Summary(";
if (summary == Signature::None) {
os << "None";
} else {
#define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
OUTPUT(Valid);
OUTPUT(Green);
OUTPUT(Red);
OUTPUT(KeyRevoked);
OUTPUT(KeyExpired);
OUTPUT(SigExpired);
OUTPUT(KeyMissing);
OUTPUT(CrlMissing);
OUTPUT(CrlTooOld);
OUTPUT(BadPolicy);
OUTPUT(SysError);
OUTPUT(TofuConflict);
os << "GpgME::Signature::Summary(";
OUTPUT(Valid);
OUTPUT(Green);
OUTPUT(Red);
OUTPUT(KeyRevoked);
OUTPUT(KeyExpired);
OUTPUT(SigExpired);
OUTPUT(KeyMissing);
OUTPUT(CrlMissing);
OUTPUT(CrlTooOld);
OUTPUT(BadPolicy);
OUTPUT(SysError);
OUTPUT(TofuConflict);
#undef OUTPUT
}
return os << ')';
}
@ -612,14 +602,10 @@ std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig)
std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags)
{
os << "GpgME::Notation::Flags(";
if (flags == Notation::NoFlags) {
os << "NoFlags";
} else {
#define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0)
OUTPUT(HumanReadable);
OUTPUT(Critical);
OUTPUT(HumanReadable);
OUTPUT(Critical);
#undef OUTPUT
}
return os << ')';
}

View File

@ -52,7 +52,6 @@ public:
VerificationResult(gpgme_ctx_t ctx, const Error &error);
explicit VerificationResult(const Error &err);
VerificationResult(const VerificationResult &other) = default;
const VerificationResult &operator=(VerificationResult other)
{
swap(other);
@ -91,7 +90,6 @@ public:
Signature();
Signature(const Signature &other) = default;
const Signature &operator=(Signature other)
{
swap(other);

View File

@ -45,7 +45,6 @@ public:
VfsMountResult(gpgme_ctx_t ctx, const Error &error, const Error &opError);
explicit VfsMountResult(const Error &err);
VfsMountResult(const VfsMountResult &other) = default;
const VfsMountResult &operator=(VfsMountResult other)
{
swap(other);

View File

@ -22,7 +22,7 @@ AM_LDFLAGS = -no-install
LDADD = ../../cpp/src/libgpgmepp.la \
../../../src/libgpgme.la @GPG_ERROR_LIBS@ \
@LDADD_FOR_TESTS_KLUDGE@ -lstdc++
-lstdc++
AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
@GPG_ERROR_CFLAGS@ @GPG_ERROR_CFLAGS@ \
@ -32,14 +32,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
run_getkey_SOURCES = run-getkey.cpp
run_keylist_SOURCES = run-keylist.cpp
run_verify_SOURCES = run-verify.cpp
if !HAVE_W32_SYSTEM
run_wkdlookup_SOURCES = run-wkdlookup.cpp
endif
if HAVE_W32_SYSTEM
programs_unix =
else
programs_unix = run-wkdlookup
endif
noinst_PROGRAMS = run-getkey run-keylist run-verify $(programs_unix)
noinst_PROGRAMS = run-getkey run-keylist run-verify

View File

@ -60,8 +60,6 @@ show_usage (int ex)
" --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
" --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
" --locate use GPGME_KEYLIST_MODE_LOCATE\n"
" --force-extern use GPGME_KEYLIST_MODE_FORCE_EXTERN\n"
" --locate-external use GPGME_KEYLIST_MODE_LOCATE_EXTERNAL\n"
, stderr);
exit (ex);
}
@ -118,12 +116,6 @@ main (int argc, char **argv)
} else if (!strcmp (*argv, "--locate")) {
argc--; argv++;
mode |= KeyListMode::Locate;
} else if (!strcmp (*argv, "--force-extern")) {
argc--; argv++;
mode |= KeyListMode::ForceExtern;
} else if (!strcmp (*argv, "--locate-external")) {
argc--; argv++;
mode |= KeyListMode::LocateExternal;
} else if (!strncmp (*argv, "--", 2)) {
show_usage (1);
}
@ -140,17 +132,11 @@ main (int argc, char **argv)
return -1;
}
ctx->setKeyListMode (mode);
if (ctx->keyListMode() != mode) {
// unfortunately, Context::setKeyListMode() does not return the error
// returned by gpgme
std::cerr << "Failed to set keylist mode. You may have used an invalid combination of options.";
return -1;
}
Error err;
const GpgME::Key key = ctx->key (*argv, err, only_secret);
std::stringstream ss;
ss << "Key " << key << " Err: " << err.asStdString() << "\n";
ss << "Key " << key << " Err: " << err.asString() << "\n";
std::cout << ss.str();

View File

@ -61,8 +61,6 @@ show_usage (int ex)
" --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
" --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
" --locate use GPGME_KEYLIST_MODE_LOCATE\n"
" --force-extern use GPGME_KEYLIST_MODE_FORCE_EXTERN\n"
" --locate-external use GPGME_KEYLIST_MODE_LOCATE_EXTERNAL\n"
, stderr);
exit (ex);
}
@ -119,17 +117,7 @@ main (int argc, char **argv)
} else if (!strcmp (*argv, "--locate")) {
argc--; argv++;
mode |= KeyListMode::Locate;
} else if (!strcmp (*argv, "--with-secret")) {
argc--; argv++;
mode |= KeyListMode::WithSecret;
} else if (!strcmp (*argv, "--force-extern")) {
argc--; argv++;
mode |= KeyListMode::ForceExtern;
} else if (!strcmp (*argv, "--locate-external")) {
argc--; argv++;
mode |= KeyListMode::LocateExternal;
} else if (!strncmp (*argv, "--", 2)) {
std::cerr << "Error: Unknown option: " << *argv << std::endl;
show_usage (1);
}
}
@ -145,25 +133,16 @@ main (int argc, char **argv)
return -1;
}
ctx->setKeyListMode (mode);
if (ctx->keyListMode() != mode) {
// unfortunately, Context::setKeyListMode() does not return the error
// returned by gpgme
std::cerr << "Failed to set keylist mode. You may have used an invalid combination of options.\n";
return -1;
}
Error err = ctx->startKeyListing (*argv, only_secret);
if (err) {
std::cout << "Error: " << err.asStdString() << "\n";
std::cout << "Error: " << err.asString() << "\n";
return -1;
}
GpgME::Key key;
std::stringstream ss;
do {
key = ctx->nextKey(err);
if (!err)
{
ss << key << "\n\n";
}
ss << key << "\n\n";
} while (!err && !key.isNull());
std::cout << ss.str();

View File

@ -38,6 +38,7 @@
#include "verificationresult.h"
#include <memory>
#include <sstream>
#include <iostream>
using namespace GpgME;

View File

@ -1,158 +0,0 @@
/*
run-wkdlookup.cpp
This file is part of GpgMEpp's test suite.
Copyright (c) 2021 g10 Code GmbH
Software engineering by Ingo Klöcker <dev@ingo-kloecker.de>
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 "context.h"
#include "data.h"
#include "defaultassuantransaction.h"
#include "key.h"
#include <memory>
#include <iostream>
#include <thread>
using namespace GpgME;
static int
show_usage (int ex)
{
fputs ("usage: run-wkdlookup <email address>\n\n"
, stderr);
exit (ex);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
if (argc) {
argc--; argv++;
}
while (argc && last_argc != argc ) {
last_argc = argc;
if (!strcmp (*argv, "--")) {
argc--; argv++;
break;
} else if (!strcmp (*argv, "--help")) {
show_usage (0);
} else if (!strncmp (*argv, "--", 2)) {
show_usage (1);
}
}
if (argc != 1) {
show_usage (1);
}
const std::string email{*argv};
GpgME::initializeLibrary();
Error err;
auto ctx = std::unique_ptr<Context>{Context::createForEngine(AssuanEngine, &err)};
if (!ctx) {
std::cerr << "Failed to get context (Error: " << err.asStdString() << ")\n";
return -1;
}
const std::string dirmngrSocket = GpgME::dirInfo("dirmngr-socket");
if ((err = ctx->setEngineFileName(dirmngrSocket.c_str()))) {
std::cerr << "Failed to set engine file name (Error: " << err.asStdString() << ")\n";
return -1;
}
if ((err = ctx->setEngineHomeDirectory(""))) {
std::cerr << "Failed to set engine home directory (Error: " << err.asStdString() << ")\n";
return -1;
}
// try to connect to dirmngr
err = ctx->assuanTransact("GETINFO version");
if (err && err.code() != GPG_ERR_ASS_CONNECT_FAILED) {
std::cerr << "Failed to start assuan transaction (Error: " << err.asStdString() << ")\n";
return -1;
}
if (err.code() == GPG_ERR_ASS_CONNECT_FAILED) {
std::cerr << "Starting dirmngr ...\n";
auto spawnCtx = std::unique_ptr<Context>{Context::createForEngine(SpawnEngine, &err)};
if (!spawnCtx) {
std::cerr << "Failed to get context for spawn engine (Error: " << err.asStdString() << ")\n";
return -1;
}
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};
err = spawnCtx->spawn(gpgconfProgram, argv,
ignoreIO, ignoreIO, ignoreIO,
Context::SpawnDetached);
if (err) {
std::cerr << "Failed to start dirmngr (Error: " << err.asStdString() << ")\n";
return -1;
}
// wait for socket to become available
int cnt = 0;
do {
++cnt;
std::cerr << "Waiting for dirmngr to start ...\n";
std::this_thread::sleep_for(std::chrono::milliseconds{250 * cnt});
err = ctx->assuanTransact("GETINFO version");
} while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5);
}
const auto cmd = std::string{"WKD_GET "} + email;
err = ctx->assuanTransact(cmd.c_str());
if (err && err.code() != GPG_ERR_NO_NAME && err.code() != GPG_ERR_NO_DATA) {
std::cerr << "Error: WKD_GET returned " << err.asStdString() << "\n";
return -1;
}
const auto transaction = std::unique_ptr<DefaultAssuanTransaction>(dynamic_cast<DefaultAssuanTransaction*>(ctx->takeLastAssuanTransaction().release()));
const auto source = transaction->firstStatusLine("SOURCE");
const auto rawData = transaction->data();
if (rawData.size() == 0) {
std::cout << "No key found for " << email << "\n";
} else {
const auto data = GpgME::Data{rawData.c_str(), rawData.size()};
const auto keys = data.toKeys(GpgME::OpenPGP);
for (const auto &key : keys) {
std::cout << "Found key for " << email << " at " << source << ":\n" << key << "\n";
}
}
return 0;
}

View File

@ -44,16 +44,4 @@ describe('GPGME context', function (){
done();
});
});
it('Error message on unsuccessful connection (timeout)', function (done) {
let prm = Gpgmejs.init({ timeout: 1 });
prm.then(
null,
function (error){
expect(error).to.be.an('error');
expect(error.code).to.equal('CONN_TIMEOUT');
done();
}
);
});
});

View File

@ -40,15 +40,7 @@ import { decode, atobArray, Utf8ArrayToStr } from './Helpers';
export class Connection{
constructor (){
this._connectionError = null;
this._connection = chrome.runtime.connectNative('gpgmejson');
this._connection.onDisconnect.addListener(() => {
if (chrome.runtime.lastError) {
this._connectionError = chrome.runtime.lastError.message;
} else {
this._connectionError = 'Disconnected without error message';
}
});
}
/**
@ -58,16 +50,9 @@ export class Connection{
if (this._connection){
this._connection.disconnect();
this._connection = null;
this._connectionError = 'Disconnect requested by gpgmejs';
}
}
/**
* Checks if the connection terminated with an error state
*/
get isDisconnected (){
return this._connectionError !== null;
}
/**
* @typedef {Object} backEndDetails
@ -99,29 +84,25 @@ export class Connection{
timeout = 1000;
}
const msg = createMessage('version');
const prm = Promise.race([
this.post(msg),
new Promise(function (resolve, reject){
setTimeout(function (){
reject(gpgme_error('CONN_TIMEOUT'));
}, timeout);
})
]);
return new Promise( function (resolve, reject) {
prm.then(function (success){
if (details === true ) {
resolve(success);
} else {
if (details === true) {
return this.post(msg);
} else {
let me = this;
return new Promise(function (resolve) {
Promise.race([
me.post(msg),
new Promise(function (resolve, reject){
setTimeout(function (){
reject(gpgme_error('CONN_TIMEOUT'));
}, timeout);
})
]).then(function (){ // success
resolve(true);
}
}, function (error) {
if (details === true ) {
reject(error);
} else {
}, function (){ // failure
resolve(false);
}
});
});
});
}
}
/**
@ -147,7 +128,7 @@ export class Connection{
}
let chunksize = message.chunksize;
const me = this;
const nativeCommunication = new Promise(function (resolve, reject){
return new Promise(function (resolve, reject){
let answer = new Answer(message);
let listener = function (msg) {
if (!msg){
@ -180,35 +161,29 @@ export class Connection{
}
};
me._connection.onMessage.addListener(listener);
me._connection.postMessage(message.message);
// check for browser messaging errors after a while
// (browsers' extension permission checks take some time)
setTimeout( () => {
if (me.isDisconnected) {
if ( me.isNativeHostUnknown === true) {
return reject(gpgme_error('CONN_NO_CONFIG'));
} else {
return reject(gpgme_error(
'CONN_NO_CONNECT', me._connectionError));
if (permittedOperations[message.operation].pinentry){
return me._connection.postMessage(message.message);
} else {
return Promise.race([
me._connection.postMessage(message.message),
function (resolve, reject){
setTimeout(function (){
me._connection.disconnect();
reject(gpgme_error('CONN_TIMEOUT'));
}, 5000);
}
}
}, 25);
]).then(function (result){
return result;
}, function (reject){
if (!(reject instanceof Error)) {
me._connection.disconnect();
return gpgme_error('GNUPG_ERROR', reject);
} else {
return reject;
}
});
}
});
if (permittedOperations[message.operation].pinentry === true) {
return nativeCommunication;
} else {
return Promise.race([
nativeCommunication,
new Promise(function (resolve, reject){
setTimeout(function (){
me.disconnect();
reject(gpgme_error('CONN_TIMEOUT'));
}, 5000);
})
]);
}
}
}
@ -237,13 +212,6 @@ class Answer{
return this._expected;
}
/**
* Checks if an error matching browsers 'host not known' messages occurred
*/
get isNativeHostUnknown () {
return this._connectionError === 'Specified native messaging host not found.';
}
/**
* Adds incoming base64 encoded data to the existing response
* @param {*} msg base64 encoded data.

View File

@ -35,14 +35,6 @@ export const err_list = {
msg: 'The nativeMessaging answer was empty.',
type: 'error'
},
'CONN_NO_CONFIG':{
msg: 'The browser does not recognize the nativeMessaging host.',
type: 'error'
},
'CONN_NATIVEMESSAGE':{
msg: 'The native messaging was not successful.',
type: 'error'
},
'CONN_TIMEOUT': {
msg: 'A connection timeout was exceeded.',
type: 'error'
@ -164,8 +156,8 @@ export function gpgme_error (code = 'GENERIC_ERROR', info){
*/
class GPGME_Error extends Error{
constructor (code = 'GENERIC_ERROR', msg=''){
const verboseErrors = ['GNUPG_ERROR', 'CONN_NATIVEMESSAGE'];
if (verboseErrors.includes(code) && typeof (msg) === 'string'){
if (code === 'GNUPG_ERROR' && typeof (msg) === 'string'){
super(msg);
} else if (err_list.hasOwnProperty(code)){
if (msg){

View File

@ -33,7 +33,7 @@ import { Connection } from './Connection';
* An unsuccessful attempt will reject as a GPGME_Error.
* @param {Object} config (optional) configuration options
* @param {Number} config.timeout set the timeout for the initial connection
* check. On some machines and operating systems a default timeout of 1000 ms is
* check. On some machines and operating systems a default timeout of 500 ms is
* too low, so a higher number might be attempted.
* @returns {Promise<GpgME>}
* @async
@ -46,17 +46,7 @@ function init ({ timeout = 1000 } = {}){
if (result === true) {
resolve(new GpgME());
} else {
if (connection._connectionError) {
if (connection.isNativeHostUnknown){
reject(gpgme_error('CONN_NO_CONFIG'));
} else {
reject(gpgme_error('CONN_NATIVEMESSAGE',
connection._connectionError)
);
}
} else {
reject(gpgme_error('CONN_TIMEOUT'));
}
reject(gpgme_error('CONN_NO_CONNECT'));
}
}, function (){ // unspecific connection error. Should not happen
reject(gpgme_error('CONN_NO_CONNECT'));

View File

@ -49,42 +49,11 @@ function unittests (){
expect(answer.info).to.be.an('Array');
expect(conn0.disconnect).to.be.a('function');
expect(conn0.post).to.be.a('function');
expect(conn0.isDisconnected).to.be.false;
done();
});
});
it('Simple connection check', function (done) {
let conn0 = new Connection;
conn0.checkConnection(false, connectionTimeout).then(
function (answer) {
expect(answer).to.be.true;
expect(conn0.isDisconnected).to.be.false;
done();
});
});
it('Connection check with backend information', function (done) {
let conn0 = new Connection;
conn0.checkConnection(true, connectionTimeout).then(
function (answer) {
expect(answer).to.be.an('Object');
expect(answer.gpgme).to.be.a('String');
expect(answer.info).to.be.an('Array');
expect(answer.info.length).to.be.above(0);
for (const item of answer.info) {
expect(item).to.have.property('protocol');
expect(item).to.have.property('fname');
expect(item).to.have.property('version');
expect(item).to.have.property('req_version');
expect(item).to.have.property('homedir');
}
expect(conn0.isDisconnected).to.be.false;
done();
});
});
it('Disconnecting', function (done) {
let conn0 = new Connection;
conn0.checkConnection(false, connectionTimeout).then(
@ -94,7 +63,6 @@ function unittests (){
conn0.checkConnection(false, connectionTimeout).then(
function (result) {
expect(result).to.be.false;
expect(conn0.isDisconnected).to.be.true;
done();
});
});

View File

@ -21,15 +21,12 @@ EXTRA_DIST = \
README \
MANIFEST.in \
gpgme.i \
helpers.c helpers.h private.h
helpers.c helpers.h private.h \
examples \
doc \
src
if RUN_GPG_TESTS
tests = tests
else
tests =
endif
SUBDIRS = . ${tests} examples doc src
SUBDIRS = . tests
.PHONY: prepare
prepare: copystamp
@ -80,7 +77,7 @@ CLEANFILES = copystamp \
# 'make distclean' clears the write bit, breaking rm -rf. Fix the
# permissions.
clean-local:
rm -rf -- build dist gpg.egg-info
rm -rf -- build
for PYTHON in $(PYTHONS); do \
find "$$(basename "$${PYTHON}")-gpg" -type d ! -perm -200 -exec chmod u+w {} ';' ; \
rm -rf -- "$$(basename "$${PYTHON}")-gpg" ; \
@ -101,12 +98,8 @@ install-exec-local:
done
uninstall-local:
set -x; \
GV=$$(echo $(VERSION) | tr - _); \
normalizedGV=$$(echo $$GV | sed s/_beta/b/); \
for PYTHON in $(PYTHONS); do \
set -x; GV=$$(echo $(VERSION) | tr - _); for PYTHON in $(PYTHONS); do \
PLATLIB="$(prefix)/$$("$${PYTHON}" -c 'import sysconfig, os; print(os.path.relpath(sysconfig.get_path("platlib", scheme="posix_prefix"), sysconfig.get_config_var("prefix")))')" ; \
rm -rf -- "$(DESTDIR)$${PLATLIB}/gpg" \
"$(DESTDIR)$${PLATLIB}"/gpg-$$GV-py*.egg-info \
"$(DESTDIR)$${PLATLIB}"/gpg-$$normalizedGV-py*.egg ; \
"$(DESTDIR)$${PLATLIB}"/gpg-$$GV-py*.egg-info ; \
done

View File

@ -1,61 +0,0 @@
# Makefile.am for the Python bindings.
# Copyright (C) 2019 g10 Code GmbH
#
# This file is part of GPGME.
#
# GPGME is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 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 Lesser General
# Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, see <https://gnu.org/licenses/>.
# SPDX-License-Identifier: LGPL-2.1-or-later
EXTRA_DIST = README rst src texinfo
if MAINTAINER_MODE
ORGSRCS = index.org gpgme-python-howto.org maintenance-mode.org \
short-history.org what-is-new.org what-was-new.org
# Make sure we have 'rst' and 'texinfo' dirs in build directory
.PHONY: the_doc_dirs gen_rst gen_texi
the_doc_dirs:
@if test ! -d rst; then echo $(MKDIR_P) rst; $(MKDIR_P) rst; fi
@if test ! -d texinfo; then echo $(MKDIR_P) texinfo; $(MKDIR_P) texinfo; fi
# Generate RST files from ORG
gen_rst:
@for f in $(ORGSRCS); do if test ! -e rst/$${f%.org}.rst \
-o rst/$${f%.org}.rst -ot $(srcdir)/src/$$f; then \
echo pandoc -f org -t rst $(srcdir)/src/$$f -o rst/$${f%.org}.rst; \
pandoc -f org -t rst $(srcdir)/src/$$f -o rst/$${f%.org}.rst; \
fi; \
done
# Generate Texinfo files from ORG
gen_texi:
@for f in $(ORGSRCS); do if test ! -e texinfo/$${f%.org}.texi \
-o texinfo/$${f%.org}.texi -ot $(srcdir)/src/$$f; then \
echo pandoc -f org -t texinfo $(srcdir)/src/$$f -o texinfo/$${f%.org}.texi; \
pandoc -f org -t texinfo $(srcdir)/src/$$f -o texinfo/$${f%.org}.texi; \
fi; \
done
all-local: gen_rst gen_texi
gen_rst gen_texi: the_doc_dirs
maintainer-clean-local:
@for f in $(ORGSRCS); do \
echo rm -f rst/$${f%.org}.rst texinfo/$${f%.org}.texi; \
rm -f rst/$${f%.org}.rst texinfo/$${f%.org}.texi; \
done
endif

View File

@ -1 +1 @@
Directory for Sphinx's built documentation.
Directory for Sphinx's built documentation.

View File

@ -15,8 +15,6 @@
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import hashlib
import time
# -- Project information -----------------------------------------------------
@ -103,7 +101,7 @@ html_static_path = ['_static']
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'GPGMEPythonBindings'
htmlhelp_basename = 'GPGMEPythonBindingsdoc'
# -- Options for LaTeX output ------------------------------------------------
@ -116,7 +114,6 @@ latex_elements = {
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
'pointsize': '12pt'
# Additional stuff for the LaTeX preamble.
#
@ -131,8 +128,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'GPGMEPythonBindings.tex',
'GPGME Python Bindings Documentation',
(master_doc, 'GPGMEPythonBindings.tex', 'GPGME Python Bindings Documentation',
'The GnuPG Hackers', 'manual'),
]
@ -154,8 +150,8 @@ man_pages = [
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'GPGMEPythonBindings', 'GPGME Python Bindings Documentation',
author, 'GPGMEPythonBindings',
'Python Bindings to the GNU Privacy Guard API.', 'Miscellaneous'),
author, 'GPGMEPythonBindings', 'One line description of project.',
'Miscellaneous'),
]
@ -164,21 +160,14 @@ texinfo_documents = [
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be an ISBN number
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
epub_identifier = 'org.gnupg.gpgme.python'
# A unique identification for the text.
#
# epub_uid = ''
stt = str(time.time())
epub_seed = "{0} {1}".format(epub_identifier, tt)
# SHA1 would be more than fine for this, but since the dimmest always panic
# about any use of SHA1 with GnuPG, we'll use SHA256.
epub_hash = hashlib.sha256(epub_seed).hexdigest()
epub_uid = 'sha256:{0}'.format(epub_hash)
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
epub_exclude_files = ['search.html']

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
.. GPGME Python Bindings documentation master file, created by
sphinx-quickstart on Wed Dec 5 09:04:47 2018.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
GPGME Python Bindings
=====================
.. toctree::
:maxdepth: 2
:caption: Contents:
Contents
--------
- `A short history of the project <short-history>`__
- `What\'s New <what-is-new>`__
- `Maintenance Mode <maintenance-mode>`__ (from January, 2019)
- `What Was New <what-was-new>`__
- `GPGME Python Bindings HOWTO <gpgme-python-howto>`__
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,90 @@
.. _maintenance-mode:
Maintenance Mode from 2019
==========================
+-----------------+------------------------------------------+
| Version: | 0.0.1 |
+-----------------+------------------------------------------+
| GPGME Version: | 1.13.0 |
+-----------------+------------------------------------------+
| Author: | Ben McGinnes <ben@gnupg.org> |
+-----------------+------------------------------------------+
| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
+-----------------+------------------------------------------+
| Language: | Australian English, British English |
+-----------------+------------------------------------------+
| xml:lang: | en-AU, en-GB, en |
+-----------------+------------------------------------------+
From the beginning of 2019 the Python bindings to GPGME will enter
maintenance mode, meaning that new features will not be added and only
bug fixes and security fixes will be made. This also means that
documentation beyond that existing at the end of 2018 will not be
developed further except to correct errors.
Though use of these bindings appears to have been quite well received,
there has been no indication of what demand there is, if any for either
financial backing of the current Python bindings development or support
contracts with g10code GmbH citing the necessity of including the
bindings.
.. _maintenance-mode-bm:
Maintainer from 2019 onward
---------------------------
How does this affect the position of GnuPG Python Bindings Maintainer?
Well, I will remain as maintainer of the bindings; but without funding
for that position, the amount of time I will be able to dedicate solely
to this task will be limited and reduced to volunteered time. As with
all volunteered time and effort in free software projects, this will be
subject to numerous external imperatives.
.. _maintenance-mode-blade-runner:
Using the Python Bindings from 2019 and beyond
----------------------------------------------
For most, if not all, Python developers using these bindings; they will
continue to "just work" the same as they always have. Expansions of
GPGME itself are usually handled by SWIG with the existing code and thus
bindings are generated properly when the bindings are installed
alongside GPGME and when the latter is built from source.
In the rare circumstances where that is not enough to address some new
addition to GPGME, then that is a bug and thus subject to the
maintenance mode provisions (i.e. it will be fixed following a bug
report being raised and your humble author will need to remember where
the timesheet template was filed, depending on how many years off such
an event is).
All the GPGME functionality will continue to be accessible via the lower
level, dynamically generated methods which match the GPGME C
documentation. While the more intuitively Pythonic higher level layer
already covers the vast majority of functionality people require with
key generation, signatures, certifications (key signing), encryption,
decryption, verification, validation, trust levels and so on.
Any wanted features lacking in the Python bindings are usually lacking
because they are missing from GPGME itself (e.g. revoking keys via the
API) and in such cases they are usually deliberately excluded. More
discussion of these issues can be found in the archives of the
`gnupg-devel mailing
list <https://lists.gnupg.org/mailman/listinfo/gnupg-devel>`__.
Any features existing in the dynamically generated layer for which
people want a specific, higher level function included to make it more
Pythonic (e.g. to avoid needing to learn or memorise cryptographic mode
values or GnuPG status code numbers), would be a feature request and
*not* a bug.
It is still worthwhile requesting it, but the addition of such a feature
would not be guaranteed and provided on a purely volunteer basis.
Expediting such a request would require funding that request.
Those with a commercial interest in expediting such a feature request
already know how to `expedite
it <https://gnupg.org/cgi-bin/procdonate.cgi?mode=preset>`__ (use the
message field to state what feature is being requested).

View File

@ -0,0 +1,166 @@
Overview
========
+-----------------+------------------------------------------+
| Version: | 0.0.1 |
+-----------------+------------------------------------------+
| GPGME Version: | 1.13.0 |
+-----------------+------------------------------------------+
| Author: | Ben McGinnes <ben@gnupg.org> |
+-----------------+------------------------------------------+
| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
+-----------------+------------------------------------------+
| Language: | Australian English, British English |
+-----------------+------------------------------------------+
| xml:lang: | en-AU, en-GB, en |
+-----------------+------------------------------------------+
The GPGME Python bindings passed through many hands and numerous phases
before, after a fifteen year journey, coming full circle to return to
the source. This is a short explanation of that journey.
.. _in-the-begining:
In the beginning
----------------
In 2002 John Goerzen released PyME; Python bindings for the GPGME module
which utilised the current release of Python of the time and SWIG. [1]_
Shortly after creating it and ensuring it worked he stopped supporting
it, though he left his work available on his Gopher site.
Keeping the flame alive
-----------------------
A couple of years later the project was picked up by Igor Belyi and
actively developed and maintained by him from 2004 to 2008. Igor\'s
whereabouts at the time of this document\'s creation are unknown, but
the current authors do hope he is well. We\'re assuming (or hoping) that
life did what life does and made continuing untenable.
Passing the torch
-----------------
In 2014 Martin Albrecht wanted to patch a bug in the PyME code and
discovered the absence of Igor. Following a discussion on the PyME
mailing list he became the new maintainer for PyME, releasing version
0.9.0 in May of that year. He remains the maintainer of the original
PyME release in Python 2.6 and 2.7 (available via PyPI).
.. _ouroboros:
Coming full circle
------------------
In 2015 Ben McGinnes approached Martin about a Python 3 version, while
investigating how complex a task this would be the task ended up being
completed. A subsequent discussion with Werner Koch led to the decision
to fold the Python 3 port back into the original GPGME release in the
languages subdirectory for non-C bindings under the module name of
``pyme3``.
In 2016 this PyME module was integrated back into the GPGME project by
Justus Winter. During the course of this work Justus adjusted the port
to restore limited support for Python 2, but not as many minor point
releases as the original PyME package supports. During the course of
this integration the package was renamed to more accurately reflect its
status as a component of GPGME. The ``pyme3`` module was renamed to
``gpg`` and adopted by the upstream GnuPG team.
In 2017 Justus departed G10code and the GnuPG team. Following this Ben
returned to maintain of gpgme Python bindings and continue building them
from that point.
.. _relics-past:
Relics of the past
==================
There are a few things, in addition to code specific factors, such as
SWIG itself, which are worth noting here.
The Annoyances of Git
---------------------
As anyone who has ever worked with git knows, submodules are horrible
way to deal with pretty much anything. In the interests of avoiding
migraines, that was skipped with addition of the PyME code to GPGME.
Instead the files were added to a subdirectory of the ``lang/``
directory, along with a copy of the entire git log up to that point as a
separate file within the ``lang/python/docs/`` directory. [2]_ As the
log for PyME is nearly 100KB and the log for GPGME is approximately 1MB,
this would cause considerable bloat, as well as some confusion, should
the two be merged.
Hence the unfortunate, but necessary, step to simply move the files. A
regular repository version has been maintained should it be possible to
implement this better in the future.
The Perils of PyPI
------------------
The early port of the Python 2 ``pyme`` module as ``pyme3`` was never
added to PyPI while the focus remained on development and testing during
2015 and early 2016. Later in 2016, however, when Justus completed his
major integration work and subsequently renamed the module from
``pyme3`` to ``gpg``, some prior releases were also provided through
PyPI.
Since these bindings require a matching release of the GPGME libraries
in order to function, it was determined that there was little benefit in
also providing a copy through PyPI since anyone obtaining the GPGME
source code would obtain the Python bindings source code at the same
time. Whereas there was the potential to sew confusion amongst Python
users installing the module from PyPI, only to discover that without the
relevant C files, header files or SWIG compiled binaries, the Python
module did them little good.
There are only two files on PyPI which might turn up in a search for
this module or a sample of its content:
#. gpg (1.8.0) - Python bindings for GPGME GnuPG cryptography library
#. pyme (0.9.0) - Python support for GPGME GnuPG cryptography library
.. _pypi-gpgme-180:
GPG 1·8·0 - Python bindings for GPGME GnuPG cryptography library
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the most recent version to reach PyPI and is the version of the
official Pyhon bindings which shipped with GPGME 1.8.0. If you have
GPGME 1.8.0 installed and *only* 1.8.0 installed, then it is probably
safe to use this copy from PyPI.
As there have been a lot of changes since the release of GPGME 1.8.0,
the GnuPG Project recommends not using this version of the module and
instead installing the current version of GPGME along with the Python
bindings included with that package.
.. _pypi-gpgme-90:
PyME 0·9·0 - Python support for GPGME GnuPG cryptography library
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the last release of the PyME bindings maintained by Martin
Albrecht and is only compatible with Python 2, it will not work with
Python 3. This is the version of the software from which the port from
Python 2 to Python 3 code was made in 2015.
Users of the more recent Python bindings will recognise numerous points
of similarity, but also significant differences. It is likely that the
more recent official bindings will feel \"more pythonic.\"
For those using Python 2, there is essentially no harm in using this
module, but it may lack a number of more recent features added to GPGME.
Footnotes
=========
.. [1]
In all likelihood this would have been Python 2.2 or possibly Python
2.3.
.. [2]
The entire PyME git log and other preceding VCS logs are located in
the ``gpgme/lang/python/docs/old-commits.log`` file.

View File

@ -0,0 +1,41 @@
.. _new-stuff:
What\'s New
===========
+-----------------+------------------------------------------+
| Version: | 0.0.1 |
+-----------------+------------------------------------------+
| GPGME Version: | 1.13.0 |
+-----------------+------------------------------------------+
| Author: | Ben McGinnes <ben@gnupg.org> |
+-----------------+------------------------------------------+
| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
+-----------------+------------------------------------------+
| Language: | Australian English, British English |
+-----------------+------------------------------------------+
| xml:lang: | en-AU, en-GB, en |
+-----------------+------------------------------------------+
Last time the most obviously new thing was adding the *What\'s New*
section to the HOWTO. Now it\'s moving it out of the HOWTO.
.. _new-stuff-1-13-0:
New in GPGME 1·13·0
-------------------
Additions since GPGME 1.12.0 include:
- Moving the *What\'s New* section out of the basic
`HOWTO <gpgme-python-howto.org>`__ document and into its own file so
as to more readily include other documents beyond that HOWTO.
- Moving the preceding, archival, segments into `another
file <what-was-new.org>`__.
- Added ``gpg.version.versionintlist`` to make it easier for Python
developers to check for a specific version number, even with beta
versions (it will drop the \"-betaN\" part).
- Added expanded detail on issues pertaining to installing for Windows
users.
- Bindings enter `maintenance mode <maintenance-mode>`__ from January,
2019.

View File

@ -0,0 +1,111 @@
.. _new-stuff:
What Was New
============
+-----------------+------------------------------------------+
| Version: | 0.0.1 |
+-----------------+------------------------------------------+
| GPGME Version: | 1.13.0 |
+-----------------+------------------------------------------+
| Author: | Ben McGinnes <ben@gnupg.org> |
+-----------------+------------------------------------------+
| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
+-----------------+------------------------------------------+
| Language: | Australian English, British English |
+-----------------+------------------------------------------+
| xml:lang: | en-AU, en-GB, en |
+-----------------+------------------------------------------+
The following are all the past *What\'s New* sections for the Python
Bindings HOWTO and other documentation.
.. _gpgme-1-12-0:
What Was New in GPGME 1·12·0
----------------------------
The most obviously new point for those reading this guide is this
section on other new things, but that's hardly important. Not given all
the other things which spurred the need for adding this section and its
subsections.
.. _new-stuff-1-12-0:
New in GPGME 1·12·0
~~~~~~~~~~~~~~~~~~~
There have been quite a number of additions to GPGME and the Python
bindings to it since the last release of GPGME with versions 1.11.0 and
1.11.1 in April, 2018.
The bullet points of new additiions are:
- an expanded section on
`installing <gpgme-python-howto#installation>`__ and
`troubleshooting <gpgme-python-howto#snafu>`__ the Python bindings.
- The release of Python 3.7.0; which appears to be working just fine
with our bindings, in spite of intermittent reports of problems for
many other Python projects with that new release.
- Python 3.7 has been moved to the head of the specified python
versions list in the build process.
- In order to fix some other issues, there are certain underlying
functions which are more exposed through the
`gpg.Context() <gpgme-python-howto#howto-get-context>`__, but ongoing
documentation ought to clarify that or otherwise provide the best
means of using the bindings. Some additions to ``gpg.core`` and the
``Context()``, however, were intended (see below).
- Continuing work in identifying and confirming the cause of
oft-reported `problems installing the Python bindings on
Windows <gpgme-python-howto#snafu-runtime-not-funtime>`__.
- GSOC: Google\'s Surreptitiously Ordered Conscription ... erm ... oh,
right; Google\'s Summer of Code. Though there were two hopeful
candidates this year; only one ended up involved with the GnuPG
Project directly, the other concentrated on an unrelated third party
project with closer ties to one of the GNU/Linux distributions than
to the GnuPG Project. Thus the Python bindings benefited from GSOC
participant Jacob Adams, who added the key\ :sub:`import` function;
building on prior work by Tobias Mueller.
- Several new methods functions were added to the gpg.Context(),
including: `key\ import <gpgme-python-howto#howto-import-key>`__,
`key\ export <gpgme-python-howto#howto-export-key>`__,
`key\ exportminimal <gpgme-python-howto#howto-export-public-key>`__
and
`key\ exportsecret <gpgme-python-howto#howto-export-secret-key>`__.
- Importing and exporting examples include versions integrated with
Marcel Fest\'s recently released `HKP for
Python <https://github.com/Selfnet/hkp4py>`__ module. Some
`additional notes on this module <gpgme-python-howto#hkp4py>`__ are
included at the end of the HOWTO.
- Instructions for dealing with semi-walled garden implementations like
ProtonMail are also included. This is intended to make things a
little easier when communicating with users of ProtonMail\'s services
and should not be construed as an endorsement of said service. The
GnuPG Project neither favours, nor disfavours ProtonMail and the
majority of this deals with interacting with the ProtonMail
keyserver.
- Semi-formalised the location where `draft
versions <gpgme-python-howto#draft-editions>`__ of this HOWTO may
periodically be accessible. This is both for the reference of others
and testing the publishing of the document itself. Renamed this file
at around the same time.
- The Texinfo documentation build configuration has been replicated
from the parent project in order to make to maintain consistency with
that project (and actually ship with each release).
- a reStructuredText (``.rst``) version is also generated for Python
developers more used to and comfortable with that format as it is the
standard Python documentation format and Python developers may wish
to use it with Sphinx. Please note that there has been no testing of
the reStructuredText version with Sphinx at all. The reST file was
generated by the simple expedient of using
`Pandoc <https://pandoc.org/>`__.
- Added a new section for `advanced or experimental
use <gpgme-python-howto#advanced-use>`__.
- Began the advanced use cases with `a
section <gpgme-python-howto#cython>`__ on using the module with
`Cython <https://cython.org/>`__.
- Added a number of new scripts to the ``example/howto/`` directory;
some of which may be in advance of their planned sections of the
HOWTO (and some are just there because it seemed like a good idea at
the time).
- Cleaned up a lot of things under the hood.

View File

@ -15,8 +15,8 @@
:CUSTOM_ID: intro
:END:
| Version: | 0.1.5 |
| GPGME Version: | 1.13.0 |
| Version: | 0.1.4 |
| GPGME Version: | 1.12.1 |
| Author: | Ben McGinnes <ben@gnupg.org> |
| Author GPG Key: | DB4724E6FA4286C92B4E55C4321E4E2373590E5D |
| Language: | Australian English, British English |
@ -397,7 +397,7 @@ both by and in order to create, the bindings (including both the
If specifying a selected number of languages to create bindings for,
try to leave Python last. Currently the majority of the other
language bindings are also preceding Python of either version when
listed alphabetically (not counting the Qt bindings).
listed alphabetically and so that just happens by default currently.
If Python is set to precede one of the other languages then it is
possible that the errors described here may interrupt the build
@ -406,12 +406,6 @@ these cases it may be preferable to configure all preferred language
bindings separately with alternative =configure= steps for GPGME using
the =--enable-languages=$LANGUAGE= option.
Alternatively =make= (or =gmake=, depending on your platform) may be
run with the the =-k= option, which tells make to keep going even if
errors are encountered. In that case the failure of one language's
set of bindings to build should not hamper another language's bindings
to build.
*** Reinstalling Responsibly
:PROPERTIES:
@ -464,8 +458,8 @@ case in most, if not all, cases.
Note that from GPGME [[https://dev.gnupg.org/rMff6ff616aea6f59b7f2ce1176492850ecdf3851e][1.12.1]] the default installation installs to each
version of Python it can find first. That is that it will currently
install for the first copies of Python versions 2.7, 3.4, 3.5, and so on
up until the current dev branch that it finds. Usually this will be in the
install for the first copies of Python versions 2.7, 3.4, 3.5, 3.6,
3.7 and 3.8 (dev branch) that it finds. Usually this will be in the
same prefix as GPGME itself, but is dictated by the =$PATH= when the
installation is performed. The above instructions can still be
performed on other python installations which the installer does not
@ -575,13 +569,6 @@ x86-64 (i.e. Intel and AMD) and ARM architectures for CPython 3.5,
3.6, 3.7 and later releases. That's the bare *minimum*, it'd probably
be higher.
Additionally, with only a binary installation used in conjunction with
the CPython installer from =python.org= the advanced options available
which utilise [[#cython][Cython]] will not be able to be used at all. Cython
depends on being able to compile the C code it generates and that too
would need to utilise a matching runtime to both the installed version
of CPython and these bindings in order to work with the bindings.
Considering all of that, what do we recommend?
1. Use a recent version of CPython; at least 3.5, but ideally 3.6 or
@ -705,22 +692,6 @@ the command =python3 -m virtualenv /path/to/install/virtual/thingy=
instead.
*** Post installation
:PROPERTIES:
:CUSTOM_ID: snafu-docs
:END:
Following installation it is recommended to move the
=post_installer.py= script from the =lang/python/examples/howto/=
directory to the =lang/python/= directory and run it. This will fix
or restore files needed by Sphinx which may be removed during a
distribution build for release. It will also generate reST files from
Org mode files with Pandoc and generate Texinfo files from Org mode
files with GNU Emacs and Org mode (in batch mode). Additionally it
will fix the UTF-8 declaration line in the Texinfo files (Emacs
expects "UTF-8" to be "utf-8").
* Fundamentals
:PROPERTIES:
:CUSTOM_ID: howto-fund-a-mental
@ -985,14 +956,6 @@ relative ease by which such key IDs can be reproduced, as demonstrated
by the Evil32 Project in 2014 (which was subsequently exploited in
2016).
Testing for whether a string in any given search is or may be a
hexadecimal value which may be missing the leading =0x= is a simple
matter of using a try/except statement which attempts to convert the
string as hex to an integer and then back to hex; then using that to
search with. Raising a ValueError simply results in treating the
string as a string. This is the method and logic utilised in the
=import-keys-hkp.py= script (see below).
*** Working with ProtonMail
:PROPERTIES:
@ -1127,7 +1090,6 @@ import sys
c = gpg.Context()
server = hkp4py.KeyServer("hkps://hkps.pool.sks-keyservers.net")
results = []
keys = []
if len(sys.argv) > 2:
pattern = " ".join(sys.argv[1:])
@ -1136,56 +1098,22 @@ elif len(sys.argv) == 2:
else:
pattern = input("Enter the pattern to search for keys or user IDs: ")
if pattern is not None:
try:
key = server.search(hex(int(pattern, 16)))
keyed = True
except ValueError as ve:
key = server.search(pattern)
keyed = False
if key is not None:
keys.append(key[0])
if keyed is True:
try:
fob = server.search(pattern)
except:
fob = None
if fob is not None:
keys.append(fob[0])
else:
pass
else:
pass
try:
keys = server.search(pattern)
print("Found {0} key(s).".format(len(keys)))
except Exception as e:
keys = []
for logrus in pattern.split():
try:
key = server.search(hex(int(logrus, 16)))
hexed = True
except ValueError as ve:
if logrus.startswith("0x") is True:
key = server.search(logrus)
hexed = False
if key is not None:
keys.append(key[0])
if hexed is True:
try:
fob = server.search(logrus)
except:
fob = None
if fob is not None:
keys.append(fob[0])
else:
pass
else:
pass
key = server.search("0x{0}".format(logrus))
keys.append(key[0])
print("Found {0} key(s).".format(len(keys)))
if len(keys) > 0:
for key in keys:
import_result = c.key_import(key.key_blob)
results.append(import_result)
for key in keys:
import_result = c.key_import(key.key_blob)
results.append(import_result)
for result in results:
if result is not None and hasattr(result, "considered") is False:
@ -1612,7 +1540,6 @@ of the entire public keybox.
#+BEGIN_SRC python -i
import gpg
import os
import os.path
import sys
@ -1620,9 +1547,6 @@ print("""
This script exports one or more public keys in minimised form.
""")
def open_0o600(path, flags):
return os.open(path, flags, mode=0o600)
c = gpg.Context(armor=True)
if len(sys.argv) >= 4:
@ -1658,7 +1582,7 @@ except:
result = c.key_export_minimal(pattern=None)
if result is not None:
with open(keyfile, "wb", opener=open_0o600) as f:
with open(keyfile, "wb") as f:
f.write(result)
else:
pass
@ -1690,9 +1614,6 @@ This script exports one or more secret keys.
The gpg-agent and pinentry are invoked to authorise the export.
""")
def open_0o600(path, flags):
return os.open(path, flags, mode=0o600)
c = gpg.Context(armor=True)
if len(sys.argv) >= 4:
@ -1742,8 +1663,9 @@ except:
result = c.key_export_secret(pattern=None)
if result is not None:
with open(keyfile, "wb", opener=open_0o600)) as f:
with open(keyfile, "wb") as f:
f.write(result)
os.chmod(keyfile, 0o600)
else:
pass
#+END_SRC
@ -2166,10 +2088,6 @@ content as a byte object, the recipient key IDs and algorithms in
=result= and the results of verifying any signatures of the data in
=verify_result=.
If =gpg.Context().decrypt(cfile, verify=False)= is called instead,
then =verify_result= will be returned as =None= and the rest remains
as described here.
** Signing text and files
:PROPERTIES:
@ -2945,7 +2863,7 @@ Save that into a file called =keycount.pyx= and then create a
=setup.py= file which contains this:
#+BEGIN_SRC python -i
from setuptools import setup
from distutils.core import setup
from Cython.Build import cythonize
setup(
@ -3028,29 +2946,33 @@ if sys.platform == "win32":
else:
gpgconfcmd = "gpgconf --list-options gpg"
process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE)
procom = process.communicate()
try:
lines = subprocess.getoutput(gpgconfcmd).splitlines()
except:
process = subprocess.Popen(gpgconfcmd.split(), stdout=subprocess.PIPE)
procom = process.communicate()
if sys.version_info[0] == 2:
lines = procom[0].splitlines()
else:
lines = procom[0].decode().splitlines()
if sys.version_info[0] == 2:
lines = procom[0].splitlines()
else:
lines = procom[0].decode().splitlines()
for line in lines:
if line.startswith("group") is True:
break
for i in range(len(lines)):
if lines[i].startswith("group") is True:
line = lines[i]
else:
pass
groups = line.split(":")[-1].replace('"', '').split(',')
group_lines = []
group_lists = []
for group in groups:
group_lines.append(group.split("="))
group_lists.append(group.split("="))
for i in range(len(groups)):
group_lines.append(groups[i].split("="))
group_lists.append(groups[i].split("="))
for glist in group_lists:
glist[1] = glist[1].split()
for i in range(len(group_lists)):
group_lists[i][1] = group_lists[i][1].split()
#+END_SRC
The result of that code is that =group_lines= is a list of lists where
@ -3130,7 +3052,7 @@ minimum required version of GPGME is in use.
For the most part the =gpg.version.versionstr= and
=gpg.version.versionlist= methods have been quite sufficient. The
former returns the same string as =pkg-config gpgme --modversion=, while the
former returns the same string as =gpgme-config --version=, while the
latter returns the major, minor and patch values in a list.
To check if the installed bindings have actually been built against
@ -3141,7 +3063,7 @@ import gpg
import subprocess
import sys
gpgme_version_call = subprocess.Popen(["pkg-config", "gpgme", "--modversion"],
gpgme_version_call = subprocess.Popen(["gpgme-config", "--version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
gpgme_version_str = gpgme_version_call.communicate()
@ -3222,6 +3144,8 @@ occur in versions which do not have the =gpgme.version.is_beta= and
Copyright © The GnuPG Project, 2018.
Copyright (C) The GnuPG Project, 2018.
** Draft Editions of this HOWTO
:PROPERTIES:
@ -3231,27 +3155,18 @@ Copyright © The GnuPG Project, 2018.
Draft editions of this HOWTO may be periodically available directly
from the author at any of the following URLs:
- [[https://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (HTML single file, AWS S3 SSL)]]
- [[http://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (HTML single file, AWS S3 no SSL)]]
- [[https://files.au.adversary.org/crypto/gpgme-python-howto-split/index.html][GPGME Python Bindings HOWTO draft (HTML multiple files, AWS S3 SSL)]]
- [[http://files.au.adversary.org/crypto/gpgme-python-howto/index.html][GPGME Python Bindings HOWTO draft (HTML multiple files, AWS S3 no SSL)]]
- [[https://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML single file, AWS S3 SSL)]]
- [[http://files.au.adversary.org/crypto/gpgme-python-howto.html][GPGME Python Bindings HOWTO draft (XHTML single file, AWS S3 no SS)]]
- [[https://files.au.adversary.org/crypto/gpgme-python-howto-split/index.html][GPGME Python Bindings HOWTO draft (XHTML multiple files, AWS S3 SSL)]]
- [[http://files.au.adversary.org/crypto/gpgme-python-howto-split/index.html][GPGME Python Bindings HOWTO draft (XHTML multiple files, AWS S3 no SSL)]]
These draft versions have been generated from this document via GNU
Emacs [[https://orgmode.org/][Org mode]] to =.texi= and [[https://www.gnu.org/software/texinfo/][GNU Texinfo]] to HTML. Though it is
All of these draft versions except for one have been generated from
this document via GNU Emacs [[https://orgmode.org/][Org mode]] and [[https://www.gnu.org/software/texinfo/][GNU Texinfo]]. Though it is
likely that the specific [[https://files.au.adversary.org/crypto/gpgme-python-howto][file]] [[http://files.au.adversary.org/crypto/gpgme-python-howto.org][version]] used will be on the same server
with the generated output formats. Occasionally I may include the Org
mode generated XHTML versions:
- [[https://files.au.adversary.org/crypto/gpgme-python-howto.xhtml][GPGME Python Bindings HOWTO draft (HTML single file, AWS S3 SSL)]]
- [[http://files.au.adversary.org/crypto/gpgme-python-howto.xhtml][GPGME Python Bindings HOWTO draft (HTML single file, AWS S3 no SSL)]]
That XHTML version, however, is exported in a way which inherits a
colour scheme from [[https://github.com/holomorph/emacs-zenburn][the author's Emacs theme]] (which is a higher contrast
version of [[http://kippura.org/zenburnpage/][Zenburn]] ported by [[https://github.com/holomorph][Holomorph]]). So it's fine for people who
prefer dark themed web pages, but not so great for everyone else.
with the generated output formats.
The GNU Texinfo and reStructured Text versions ship with the software,
while the GNU Emacs Info version is generated from the Texinfo
while the GNU Emacs Info verseion is generated from the Texinfo
version using GNU Texinfo or GNU Makeinfo. The Texinfo format is
generated from the original Org mode source file in Org mode itself
either within GNU Emacs or via the command line by invoking Emacs in
@ -3262,63 +3177,20 @@ batch mode:
emacs gpgme-python-howto --batch -f org-texinfo-export-to-texinfo --kill
#+END_SRC
The reStructuredText format is also generated from the Org mode source
The reStructuredText format is also generated from the Org-mode source
file, except it is generated using [[https://pandoc.org][Pandoc]] with either of the following
commands (depending on the filename):
commands:
#+BEGIN_SRC shell
pandoc -f org -t rst+smart -o gpgme-python-howto.rst gpgme-python-howto.org
pandoc -f org -t rst+smart -o gpgme-python-howto.rst gpgme-python-howto
#+END_SRC
Note that the Org mode source files are identified as such via a mode
line at the top of each file and have had their =.org= file extensions
dropped in order to make scripted generation of output formats easier
and not require renaming files post-conversion.
Due to a bug in Org mode's texinfo conversion method, the recommended
steps for generating the Texinfo files for all the files in the
=lang/python/doc/src/= directory are as follows:
#+BEGIN_SRC shell
for x in * ; do
emacs $x --batch -f org-texinfo-export-to-texinfo --kill
cat $x.texi | sed -e 's/@documentencoding UTF-8/@documentencoding utf-8/g' > ../texinfo/$x.texi
pandoc -f org -t rst+smart -o ../rst/$x.rst $x
done ;
rm -fv *.texi
cd ../texinfo
mkdir info
mkdir html
for x in *.texi ; do
makeinfo -v $x
makeinfo --html --no-split $x
done ;
mv *.info info/
mv *.html html/
#+END_SRC
This code snippet includes the generation of the reStructuredText
files and would be expected to be run from the =doc/src/= directory
containing the Org mode source files. It also assumes that the
commands are being run on POSIX compliant systems with basic tools
like sed, the Bourne shell and GNU Emacs[fn:6] available. The code
snippet also includes the steps for generating the Emacs Info files
and HTML files from the Texinfo files. Using reStructuredText files
with Sphinx is best left for the documentation of that project.
In addition to these there is a significantly less frequently updated
version as a HTML [[https://files.au.adversary.org/crypto/gpgme-python/dita/webhelp/index.html][WebHelp site]] (AWS S3 SSL); generated from DITA XML
version as a HTML [[https://files.au.adversary.org/crypto/gpgme-python-howto/webhelp/index.html][WebHelp site]] (AWS S3 SSL); generated from DITA XML
source files, which can be found in [[https://dev.gnupg.org/source/gpgme/browse/ben%252Fhowto-dita/][an alternative branch]] of the GPGME
git repository.
Various generated output formats may occasionally be found in
subdirectories of the [[https://s3.amazonaws.com/files.au.adversary.org/crypto/gpgme-python][gpgme-python]] directory. In particular within
the [[https://s3.amazonaws.com/files.au.adversary.org/crypto/gpgme-python/dita][DITA]], [[https://s3.amazonaws.com/files.au.adversary.org/crypto/gpgme-python/rst][reStructuredText]] and [[https://s3.amazonaws.com/files.au.adversary.org/crypto/gpgme-python/texinfo][Texinfo]] subdirectories. The =rst=
directory contains output files generated with Sphinx and may include a
considerable number of its possible output formats, but there are no
guarantees as to how recent these are or even if they are present.
These draft editions are not official documents and the version of
documentation in the master branch or which ships with released
versions is the only official documentation. Nevertheless, these
@ -3372,8 +3244,3 @@ restricted servers which only advertise either HTTP or HTTPS end
points and not HKP or HKPS end points must still be identified as as
HKP or HKPS within the Python Code. The =hkp4py= module will rewrite
these appropriately when the connection is made to the server.
[fn:6] Okay, Emacs might not necessarily qualify as a basic tool, but
it is common enough that having it installed on a system isn't too
great an expectation, nor is it difficult to add to most POSIX
systems, even if the users of those systems do not personally use it.

View File

@ -93,43 +93,3 @@ basis. Expediting such a request would require funding that request.
Those with a commercial interest in expediting such a feature request
already know how to [[https://gnupg.org/cgi-bin/procdonate.cgi?mode=preset][expedite it]] (use the message field to state what
feature is being requested).
** Documentation formats
:PROPERTIES:
:CUSTOM_ID: docs
:END:
The documentation has been written in Org mode for GNU Emacs, with
both Texinfo and reStructuredText formats generated from that. The
Texinfo files are intended for use with the rest of the GnuPG
documentation; while the reStructuredText files are intended for use
with Docutils and Sphinx, as with other Python projects.
*** Cautionary Notes regarding Sphinx and EPUB
:PROPERTIES:
:CUSTOM_ID: sphinx-made-epubs-suck
:END:
Though Python's Docutils in conjunction with Sphinx is capable of
generating some very useful HTML sites, as proven by [[https://readthedocs.org/][Read the Docs]] and
the [[https://docs.python.org/][Python documentation]], there are a number of output formats it does
not handle well. At the top of the list of things it manages to break
so atrociously as to be embarassing is the [[http://idpf.org/epub][EPUB 3]] format.
The automatically generated EPUB of the CPython documentation always
contains hundreds of validation errors and even the modest amount of
documentation here [[https://files.au.adversary.org.s3.amazonaws.com/crypto/gpgme-python/rst/epub/GPGMEPythonBindings.epub][produced a file]] with approximately thirty
validation errors. As the volume of documentation content increases,
so does the induced errors. Whereas Texinfo doesn't produce EPUB
output at all, nor does Org-mode.
Should there ever be genuine demand for this format, lodge a [[https://dev.gnupg.org/maniphest/task/edit/form/4/][feature
request]] case marked for [[https://dev.gnupg.org/p/BenM/][my]] attention. The means of generating such
files flawlessly is already available, but is not yet part of the
GnuPG build system. Nor is it integrated with a means of converting
Org mode input files to the relevant base format automatically, as can
already be done when converting Org to reStructuredText or Org to
Texinfo. As a certain amount of work would be required to get it
done, there would need to be clear demand for that work to be done.

Some files were not shown because too many files have changed in this diff Show More