[Pkg-gnupg-commit] [gpgme] 01/09: imported cleanup+bugfixes from upstream

Daniel Kahn Gillmor dkg at fifthhorseman.net
Fri Aug 18 02:29:19 UTC 2017


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch master
in repository gpgme.

commit 05c4c72dda62c02d3c99985267ff4909d4f684ef
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Thu Aug 17 21:06:02 2017 -0400

    imported cleanup+bugfixes from upstream
---
 ...003-tests-Make-error-message-more-helpful.patch |   27 +
 ...004-python-build-Reinstate-prepare-target.patch |  106 +
 ...ython-Generate-files-into-build-directory.patch |  239 +
 ...006-python-Fix-vpath-builds-fix-distcheck.patch |  334 ++
 .../0007-python-simplify-build-some-fixups.patch   | 5970 ++++++++++++++++++++
 ...0008-python-support-.pydistutils.cfg-mode.patch |  101 +
 ...o-not-use-check-local-magic-as-dependency.patch |   98 +
 ...10-python-Remove-usage-of-PYTHON_VERSIONS.patch |  111 +
 .../0011-python-Remove-unneeded-stats-copy.patch   |   30 +
 ...-Read-gpg-error.h-using-the-pre-processor.patch |  131 +
 ...thon-Support-alternatate-libdir-for-tests.patch |   63 +
 debian/patches/0014-python-Fix-distcheck.patch     |   30 +
 debian/patches/0015-python-Prune-CLEANFILES.patch  |   27 +
 ...ython-fix-run-tests-missing-python_libdir.patch |   28 +
 ...autoconf-pre-processor-when-building-via-.patch |   55 +
 .../0018-tests-Update-encrypted-sample-files.patch |   80 +
 ...mprove-doc-on-passphrase_cb-pinentry-mode.patch |   45 +
 ...core-Don-t-split-gpgconf-strings-on-comma.patch |   40 +
 .../0021-qt-tests-Don-t-use-internal-API.patch     |  153 +
 ...022-qt-Undeprecate-API-that-I-find-useful.patch |   92 +
 .../0023-qt-Add-a-missing-include-functional.patch |   33 +
 debian/patches/0024-qt-Stop-agent-on-clean.patch   |   24 +
 .../patches/0025-tests-Harmonize-test-suites.patch |   93 +
 ...sure-to-kill-all-previously-running-daemo.patch |   73 +
 ...0027-python-Fix-test-environment-creation.patch |   25 +
 ...0028-tests-Remove-remnants-of-check-local.patch |   35 +
 .../0029-python-Fix-build-in-certain-cases.patch   |   30 +
 .../patches/0030-core-Sort-the-status-table.patch  |   85 +
 ...p-Fix-CMake-config-library-name-for-GPGME.patch |   28 +
 debian/patches/0032-Fix-some-shadow-warnings.patch |   38 +
 ...lify-parsing-of-STATUS_ERROR-in-decrypt.c.patch |  127 +
 ...-CANCELED-and-BAD_PASSPHRASE-error-code-o.patch |   78 +
 ...Return-NO_SECKEY-error-code-on-decryption.patch |   86 +
 ...printf-compiler-warning-for-an-error-case.patch |   25 +
 debian/patches/0037-Sync-autogen.sh.patch          |  245 +
 ...038-tests-Make-agent-spawning-more-robust.patch |   54 +
 debian/patches/0039-tests-Fix-blunder.patch        |   25 +
 debian/patches/0040-tests-Fix-distcheck.patch      |   25 +
 ...ore-Fix-status-parsing-for-decrypt-verify.patch |   61 +
 .../0042-doc-Add-more-tofu-documentation.patch     |  104 +
 .../0043-doc-Clarify-import-keys-operation.patch   |   92 +
 ...doc-Clarify-import-keys-operation-further.patch |   42 +
 debian/patches/series                              |   42 +
 43 files changed, 9230 insertions(+)

diff --git a/debian/patches/0003-tests-Make-error-message-more-helpful.patch b/debian/patches/0003-tests-Make-error-message-more-helpful.patch
new file mode 100644
index 0000000..27066e5
--- /dev/null
+++ b/debian/patches/0003-tests-Make-error-message-more-helpful.patch
@@ -0,0 +1,27 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 28 Mar 2017 16:30:03 +0200
+Subject: tests: Make error message more helpful.
+
+* tests/gpg/t-keylist.c (main): Print number of returned and expected
+keys.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit a13e4abe9463579ef23d1acea39a093abfc6528d)
+---
+ tests/gpg/t-keylist.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tests/gpg/t-keylist.c b/tests/gpg/t-keylist.c
+index 6ee023c..8a32f9b 100644
+--- a/tests/gpg/t-keylist.c
++++ b/tests/gpg/t-keylist.c
+@@ -568,7 +568,8 @@ main (int argc, char **argv)
+ 
+   if (keys[i].fpr)
+     {
+-      fprintf (stderr, "Less keys returned than expected\n");
++      fprintf (stderr, "Less keys (%d) returned than expected (%d)\n",
++	       i, DIM (keys) - 1);
+       exit (1);
+     }
+ 
diff --git a/debian/patches/0004-python-build-Reinstate-prepare-target.patch b/debian/patches/0004-python-build-Reinstate-prepare-target.patch
new file mode 100644
index 0000000..c520190
--- /dev/null
+++ b/debian/patches/0004-python-build-Reinstate-prepare-target.patch
@@ -0,0 +1,106 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Tue, 28 Mar 2017 21:55:59 +0300
+Subject: python,build: Reinstate prepare target.
+
+* lang/python/Makefile.am: Fix 'prepare' target.
+* lang/python/setup.py.in: Use 'abs_top_builddir' instead of guessing
+the path.
+--
+
+'prepare' will prepare target at PREPAREDIR.  The automake integration
+will also make use of prepare target.  Downstream distributors may
+also make use of prepare target.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 9786e3a96e6772166f3523e74a748b9db20fae7c)
+---
+ lang/python/Makefile.am | 25 +++++++++++++++----------
+ lang/python/setup.py.in |  9 +++++----
+ 2 files changed, 20 insertions(+), 14 deletions(-)
+
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index d91ead9..a18a014 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -44,17 +44,22 @@ COPY_FILES_GPG = \
+ 	$(srcdir)/gpg/results.py \
+ 	$(srcdir)/gpg/util.py
+ 
++.PHONY: prepare
++prepare:
++	test -n "$(PREPAREDIR)"
++	$(MKDIR_P)              "$(PREPAREDIR)/gpg"
++	cp -R $(COPY_FILES)     "$(PREPAREDIR)"
++	cp setup.py             "$(PREPAREDIR)"
++	cp gpg/version.py       "$(PREPAREDIR)/gpg"
++	ln -sf "$(abs_top_srcdir)/src/data.h" "$(PREPAREDIR)"
++	ln -sf "$(abs_top_builddir)/config.h" "$(PREPAREDIR)"
++	cp -R $(COPY_FILES_GPG) "$(PREPAREDIR)/gpg"
++
+ # For VPATH builds we need to copy some files because Python's
+ # distutils are not VPATH-aware.
+ copystamp: $(COPY_FILES) $(COPY_FILES_GPG)
+ 	set -e ; for VERSION in $(PYTHON_VERSIONS); do \
+-	  $(MKDIR_P)              python$${VERSION}-gpg/gpg ; \
+-	  cp -R $(COPY_FILES)     python$${VERSION}-gpg ; \
+-	  cp setup.py             python$${VERSION}-gpg ; \
+-	  cp gpg/version.py       python$${VERSION}-gpg/gpg ; \
+-	  ln -sf "$(abs_top_srcdir)/src/data.h" python$${VERSION}-gpg ; \
+-	  ln -sf "$(abs_top_builddir)/config.h" python$${VERSION}-gpg ; \
+-	  cp -R $(COPY_FILES_GPG) python$${VERSION}-gpg/gpg ; \
++	  $(MAKE) PREPAREDIR=python$${VERSION}-gpg prepare; \
+ 	done
+ 	touch $@
+ 
+@@ -63,6 +68,7 @@ all-local: copystamp
+ 	  PYTHON="$$1" ; shift ; \
+ 	  cd python$${VERSION}-gpg && \
+ 	  CFLAGS="$(CFLAGS)" \
++	  abs_top_builddir="$(abs_top_builddir)" \
+ 	    $$PYTHON setup.py build --verbose ; \
+ 	  cd .. ; \
+ 	done
+@@ -71,12 +77,10 @@ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
+ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+ 	cd python$(PYTHON_VERSION)-gpg && \
+ 	CFLAGS="$(CFLAGS)" \
++	abs_top_builddir="$(abs_top_builddir)" \
+ 	  $(PYTHON) setup.py sdist --verbose
+ 	gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz
+ 
+-.PHONY: prepare
+-prepare: copystamp
+-
+ .PHONY: sdist
+ sdist: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
+        python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
+@@ -104,6 +108,7 @@ install-exec-local:
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
+ 	  cd python$${VERSION}-gpg ; \
++	  abs_top_builddir="$(abs_top_builddir)" \
+ 	  $$PYTHON setup.py install \
+ 	  --prefix $(DESTDIR)$(prefix) \
+ 	  --record files.txt \
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index bf4efa3..8ddbf27 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -34,12 +34,13 @@ in_tree = False
+ extra_swig_opts = []
+ extra_macros = dict()
+ 
+-if os.path.exists("../../../src/gpgme-config"):
++abs_top_builddir = os.environ.get("abs_top_builddir")
++if abs_top_builddir:
+     # In-tree build.
+     in_tree = True
+-    gpgme_config = ["../../../src/gpgme-config"] + gpgme_config_flags
+-    gpgme_h = "../../../src/gpgme.h"
+-    library_dirs = ["../../../src/.libs"] # XXX uses libtool internals
++    gpgme_config = [os.path.join(abs_top_builddir, "src/gpgme-config")] + gpgme_config_flags
++    gpgme_h = os.path.join(abs_top_builddir, "src/gpgme.h")
++    library_dirs = [os.path.join(abs_top_builddir, "src/.libs")] # XXX uses libtool internals
+     extra_macros.update(
+         HAVE_CONFIG_H=1,
+         HAVE_DATA_H=1,
diff --git a/debian/patches/0005-python-Generate-files-into-build-directory.patch b/debian/patches/0005-python-Generate-files-into-build-directory.patch
new file mode 100644
index 0000000..9c81ed1
--- /dev/null
+++ b/debian/patches/0005-python-Generate-files-into-build-directory.patch
@@ -0,0 +1,239 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Sun, 2 Apr 2017 02:29:52 +0300
+Subject: python: Generate files into build directory
+
+* lang/python/setup.py.in: Generate files within BuildExtFirstHack
+adjust build flags at this point instead of global.
+* lang/python/Makefile.am: Remove logic of separate source directory per
+python version in favor of build directory.
+* lang/python/tests/run-tests.py: Adjust build directory location.
+--
+
+Generate files into build directory, leaving the source directory clean.
+Use the same source directory for multiple python version build. Result
+of 'prepare' target is a standard distutil layout that can be used
+easily by downstream to build all python targets in-place.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 801d7d8c5dd530d26ad6c4bcc94d986e6e022da4)
+---
+ lang/python/Makefile.am        | 79 +++++++++++++++---------------------------
+ lang/python/setup.py.in        | 48 +++++++++++++++++++------
+ lang/python/tests/run-tests.py |  1 -
+ 3 files changed, 64 insertions(+), 64 deletions(-)
+
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index a18a014..b9145f5 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -27,70 +27,45 @@ EXTRA_DIST = \
+ 
+ SUBDIRS = . tests
+ 
+-COPY_FILES = \
+-	$(srcdir)/gpgme.i \
+-	$(srcdir)/README \
+-	$(srcdir)/MANIFEST.in \
+-	$(srcdir)/gpgme-h-clean.py \
+-	$(srcdir)/examples \
+-	$(srcdir)/helpers.c $(srcdir)/helpers.h $(srcdir)/private.h
+-
+-COPY_FILES_GPG = \
+-	$(srcdir)/gpg/callbacks.py \
+-	$(srcdir)/gpg/constants \
+-	$(srcdir)/gpg/core.py \
+-	$(srcdir)/gpg/errors.py \
+-	$(srcdir)/gpg/__init__.py \
+-	$(srcdir)/gpg/results.py \
+-	$(srcdir)/gpg/util.py
+-
+ .PHONY: prepare
+-prepare:
+-	test -n "$(PREPAREDIR)"
+-	$(MKDIR_P)              "$(PREPAREDIR)/gpg"
+-	cp -R $(COPY_FILES)     "$(PREPAREDIR)"
+-	cp setup.py             "$(PREPAREDIR)"
+-	cp gpg/version.py       "$(PREPAREDIR)/gpg"
+-	ln -sf "$(abs_top_srcdir)/src/data.h" "$(PREPAREDIR)"
+-	ln -sf "$(abs_top_builddir)/config.h" "$(PREPAREDIR)"
+-	cp -R $(COPY_FILES_GPG) "$(PREPAREDIR)/gpg"
++prepare: copystamp
+ 
+ # For VPATH builds we need to copy some files because Python's
+ # distutils are not VPATH-aware.
+-copystamp: $(COPY_FILES) $(COPY_FILES_GPG)
+-	set -e ; for VERSION in $(PYTHON_VERSIONS); do \
+-	  $(MAKE) PREPAREDIR=python$${VERSION}-gpg prepare; \
+-	done
++copystamp:
++	ln -sf "$(abs_top_srcdir)/src/data.h" .
++	ln -sf "$(abs_top_builddir)/config.h" .
+ 	touch $@
+ 
+ all-local: copystamp
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
+-	  cd python$${VERSION}-gpg && \
+ 	  CFLAGS="$(CFLAGS)" \
+ 	  abs_top_builddir="$(abs_top_builddir)" \
+-	    $$PYTHON setup.py build --verbose ; \
+-	  cd .. ; \
++	    $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
+ 	done
+ 
+-python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
+ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+-	cd python$(PYTHON_VERSION)-gpg && \
++	$(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
+ 	CFLAGS="$(CFLAGS)" \
+ 	abs_top_builddir="$(abs_top_builddir)" \
+-	  $(PYTHON) setup.py sdist --verbose
+-	gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz
++	  $(PYTHON) setup.py sdist --verbose --dist-dir=python$(PYTHON_VERSION)-gpg-dist \
++		--manifest=python$(PYTHON_VERSION)-gpg-dist/MANIFEST
++	gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz
+ 
+ .PHONY: sdist
+-sdist: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
+-       python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
++sdist:	python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
+ 
+ .PHONY: upload
+-upload: python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz \
+-        python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc
++upload: python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz \
++        python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz.asc
+ 	twine upload $^
+ 
+-CLEANFILES = copystamp
++CLEANFILES = copystamp \
++	config.h \
++	data.h \
++	files.txt \
++	install_files.txt
+ 
+ # Remove the rest.
+ #
+@@ -104,22 +79,22 @@ clean-local:
+ 	done
+ 
+ install-exec-local:
+-	rm -f install_files.txt
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
+-	  cd python$${VERSION}-gpg ; \
+ 	  abs_top_builddir="$(abs_top_builddir)" \
+-	  $$PYTHON setup.py install \
+-	  --prefix $(DESTDIR)$(prefix) \
++	  $$PYTHON setup.py \
++	  build \
++	  --build-base=python$${VERSION}-gpg \
++	  install \
++	  --prefix "$(DESTDIR)$(prefix)" \
+ 	  --record files.txt \
+ 	  --verbose ; \
+-	  cat files.txt >> ../install_files.txt ; \
++	  cat files.txt >> install_files.txt ; \
+ 	  rm files.txt ; \
+-	  cd .. ; \
+ 	done
+-	$(MKDIR_P) $(DESTDIR)$(pythondir)/gpg
+-	mv install_files.txt $(DESTDIR)$(pythondir)/gpg
++	$(MKDIR_P) "$(DESTDIR)$(pythondir)/gpg"
++	mv install_files.txt "$(DESTDIR)$(pythondir)/gpg"
+ 
+ uninstall-local:
+-	xargs <$(DESTDIR)$(pythondir)/gpg/install_files.txt -- rm -rf --
+-	rm -rf -- $(DESTDIR)$(pythondir)/gpg
++	xargs < "$(DESTDIR)$(pythondir)/gpg/install_files.txt" -- rm -rf --
++	rm -rf -- "$(DESTDIR)$(pythondir)/gpg"
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index 8ddbf27..6692de6 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -21,6 +21,7 @@
+ from distutils.core import setup, Extension
+ import os, os.path, sys
+ import glob
++import shutil
+ import subprocess
+ 
+ # Out-of-tree build of the gpg bindings.
+@@ -89,14 +90,6 @@ if not os.path.exists(gpg_error_h):
+         glob.glob(os.path.join(gpg_error_prefix, "include",
+                                "*", "gpg-error.h"))[0]
+ 
+-print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
+-
+-# Cleanup gpgme.h from deprecated functions and typedefs.
+-subprocess.check_call([sys.executable, "gpgme-h-clean.py", gpgme_h],
+-                      stdout=open("gpgme.h", "w"))
+-subprocess.check_call([sys.executable, "gpgme-h-clean.py", gpg_error_h],
+-                      stdout=open("errors.i", "w"))
+-
+ define_macros = []
+ libs = getconfig('libs')
+ 
+@@ -149,14 +142,47 @@ if uname_s.startswith("MINGW32"):
+ # http://stackoverflow.com/questions/12491328/python-distutils-not-include-the-swig-generated-module
+ from distutils.command.build import build
+ class BuildExtFirstHack(build):
++
++    def _generate(self):
++        print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
++
++        # Cleanup gpgme.h from deprecated functions and typedefs.
++        # Keep timestamp to avoid rebuild
++        if not os.path.exists(self.build_base):
++            os.makedirs(self.build_base)
++
++        for src, dst in (
++            (gpgme_h, os.path.join(self.build_base, "gpgme.h")),
++            (gpg_error_h, os.path.join(self.build_base, "errors.i"))
++        ):
++            subprocess.check_call([sys.executable, "gpgme-h-clean.py", src],
++                                  stdout=open(dst, "w"))
++            shutil.copystat(src, dst)
++
++        # Copy due to http://bugs.python.org/issue2624
++        # Avoid creating in srcdir
++        shutil.copy2("gpgme.i", self.build_base)
++
+     def run(self):
++        self._generate()
++
++        # Append generated files via build_base
++        if not os.path.exists(os.path.join(self.build_lib, "gpg")):
++            os.makedirs(os.path.join(self.build_lib, "gpg"))
++
++        swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
++        swig_opts.extend(['-I' + self.build_base, '-outdir', os.path.join(self.build_lib, 'gpg')])
++        include_dirs.append(self.build_base)
++
+         self.run_command('build_ext')
+         build.run(self)
+ 
+ py3 = [] if sys.version_info.major < 3 else ['-py3']
+-swige = Extension("gpg._gpgme", ["gpgme.i", "helpers.c"],
+-                  swig_opts = ['-threads',
+-                               '-outdir', 'gpg'] + py3 + extra_swig_opts,
++swig_sources = ['helpers.c']
++swig_opts = ['-threads'] + py3 + extra_swig_opts
++swige = Extension("gpg._gpgme",
++                  sources = swig_sources,
++                  swig_opts = swig_opts,
+                   include_dirs = include_dirs,
+                   define_macros = define_macros,
+                   library_dirs = library_dirs,
+diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py
+index c4af526..9721997 100644
+--- a/lang/python/tests/run-tests.py
++++ b/lang/python/tests/run-tests.py
+@@ -71,7 +71,6 @@ for interpreter in args.interpreters:
+ 
+     pattern = os.path.join(args.builddir, "..",
+                            "python{0}-gpg".format(version),
+-                           "build",
+                            "lib*"+version)
+     builddirs = glob.glob(pattern)
+     if len(builddirs) == 0:
diff --git a/debian/patches/0006-python-Fix-vpath-builds-fix-distcheck.patch b/debian/patches/0006-python-Fix-vpath-builds-fix-distcheck.patch
new file mode 100644
index 0000000..1648de3
--- /dev/null
+++ b/debian/patches/0006-python-Fix-vpath-builds-fix-distcheck.patch
@@ -0,0 +1,334 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 3 Apr 2017 15:44:14 +0200
+Subject: python: Fix vpath builds, fix distcheck.
+
+* lang/python/gpgme-h-clean.py: Delete file.
+* lang/python/MANIFEST.in: Adapt accordingly.
+* lang/python/Makefile.am (EXTRA_DIST): Likewise.
+(COPY_FILES_GPG): Bring variable back.
+(copystamp): Copy files.
+(clean-local): Delete copied files.
+(install-exec-local): Do not create and install list of installed
+files.
+(uninstall-local): Instead, create some explicit rules to uninstall
+the extension.
+* lang/python/setup.py.in: Parse arguments.  Locate files either in
+the source directory, or in the build base directory.  Inline the code
+from 'gpgme-h-clean.py'.  Copy 'helpers.c', add source directory as
+include directory.
+
+Fixes-commit: 801d7d8c5dd530d26ad6c4bcc94d986e6e022da4
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit e7d9c0c3d773f826dbd2ed417d04e25c410f3374)
+---
+ lang/python/MANIFEST.in      |  2 +-
+ lang/python/Makefile.am      | 31 ++++++++++++-----
+ lang/python/gpgme-h-clean.py | 53 -----------------------------
+ lang/python/setup.py.in      | 81 +++++++++++++++++++++++++++++++++++++-------
+ 4 files changed, 92 insertions(+), 75 deletions(-)
+ delete mode 100755 lang/python/gpgme-h-clean.py
+
+diff --git a/lang/python/MANIFEST.in b/lang/python/MANIFEST.in
+index 8f63640..ff38172 100644
+--- a/lang/python/MANIFEST.in
++++ b/lang/python/MANIFEST.in
+@@ -1,4 +1,4 @@
+ recursive-include examples *.py
+-include gpgme-h-clean.py gpgme.i
++include gpgme.i
+ include helpers.c helpers.h private.h
+ recursive-include gpg *.py
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index b9145f5..42beeee 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -21,12 +21,20 @@ EXTRA_DIST = \
+ 	MANIFEST.in \
+ 	gpgme.i \
+ 	helpers.c helpers.h private.h \
+-	gpgme-h-clean.py \
+ 	examples \
+ 	gpg
+ 
+ SUBDIRS = . tests
+ 
++COPY_FILES_GPG = \
++	$(srcdir)/gpg/callbacks.py \
++	$(srcdir)/gpg/constants \
++	$(srcdir)/gpg/core.py \
++	$(srcdir)/gpg/errors.py \
++	$(srcdir)/gpg/__init__.py \
++	$(srcdir)/gpg/results.py \
++	$(srcdir)/gpg/util.py
++
+ .PHONY: prepare
+ prepare: copystamp
+ 
+@@ -35,12 +43,14 @@ prepare: copystamp
+ copystamp:
+ 	ln -sf "$(abs_top_srcdir)/src/data.h" .
+ 	ln -sf "$(abs_top_builddir)/config.h" .
++	if test $(srcdir) != . ; then cp -R $(COPY_FILES_GPG) gpg ; fi
+ 	touch $@
+ 
+ all-local: copystamp
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
+ 	  CFLAGS="$(CFLAGS)" \
++	  srcdir="$(srcdir)" \
+ 	  abs_top_builddir="$(abs_top_builddir)" \
+ 	    $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
+ 	done
+@@ -48,6 +58,7 @@ all-local: copystamp
+ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+ 	$(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
+ 	CFLAGS="$(CFLAGS)" \
++	srcdir="$(srcdir)" \
+ 	abs_top_builddir="$(abs_top_builddir)" \
+ 	  $(PYTHON) setup.py sdist --verbose --dist-dir=python$(PYTHON_VERSION)-gpg-dist \
+ 		--manifest=python$(PYTHON_VERSION)-gpg-dist/MANIFEST
+@@ -73,6 +84,12 @@ CLEANFILES = copystamp \
+ # permissions.
+ clean-local:
+ 	rm -rf -- build
++	if test $(srcdir) != . ; then \
++	  find gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
++	  for FILE in $(COPY_FILES_GPG); do \
++	    rm -rf -- gpg/$$(basename $$FILE) ; \
++	  done \
++	fi
+ 	for VERSION in $(PYTHON_VERSIONS); do \
+ 	  find python$${VERSION}-gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+ 	  rm -rf -- python$${VERSION}-gpg ; \
+@@ -81,20 +98,18 @@ clean-local:
+ install-exec-local:
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
++	  srcdir="$(srcdir)" \
+ 	  abs_top_builddir="$(abs_top_builddir)" \
+ 	  $$PYTHON setup.py \
+ 	  build \
+ 	  --build-base=python$${VERSION}-gpg \
+ 	  install \
+ 	  --prefix "$(DESTDIR)$(prefix)" \
+-	  --record files.txt \
+ 	  --verbose ; \
+-	  cat files.txt >> install_files.txt ; \
+-	  rm files.txt ; \
+ 	done
+-	$(MKDIR_P) "$(DESTDIR)$(pythondir)/gpg"
+-	mv install_files.txt "$(DESTDIR)$(pythondir)/gpg"
+ 
+ uninstall-local:
+-	xargs < "$(DESTDIR)$(pythondir)/gpg/install_files.txt" -- rm -rf --
+-	rm -rf -- "$(DESTDIR)$(pythondir)/gpg"
++	GV=$$(echo $(VERSION) | tr - _); for PV in $(PYTHON_VERSIONS); do \
++	  rm -rf -- "$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg" \
++"$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg-$$GV-py$$PV.egg-info" ; \
++	done
+diff --git a/lang/python/gpgme-h-clean.py b/lang/python/gpgme-h-clean.py
+deleted file mode 100755
+index 52f8676..0000000
+--- a/lang/python/gpgme-h-clean.py
++++ /dev/null
+@@ -1,53 +0,0 @@
+-#!/usr/bin/env python
+-
+-# Copyright (C) 2016 g10 Code GmbH
+-# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-import sys, re
+-
+-if len(sys.argv) != 2:
+-    sys.stderr.write("Usage: %s path/to/[gpgme|gpg-error].h\n" % sys.argv[0])
+-    sys.exit(1)
+-
+-deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
+-                         + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
+-                         re.S)
+-line_break = re.compile(';|\\$|\\x0c|^\s*#|{');
+-
+-if 'gpgme.h' in sys.argv[1]:
+-    gpgme = open(sys.argv[1])
+-    tmp = gpgme.readline()
+-    text = ''
+-    while tmp:
+-        text += re.sub(' class ', ' _py_obsolete_class ', tmp)
+-        if line_break.search(tmp):
+-            if not deprec_func.search(text):
+-                sys.stdout.write(text)
+-            text = ''
+-        tmp = gpgme.readline()
+-    sys.stdout.write(text)
+-    gpgme.close()
+-else:
+-    filter_re = re.compile(r'GPG_ERR_[^ ]* =')
+-    rewrite_re = re.compile(r' *(.*) = .*')
+-    for line in open(sys.argv[1]):
+-        if not filter_re.search(line):
+-            continue
+-        print(rewrite_re.sub(r'%constant long \1 = \1;', line.strip()))
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index 6692de6..2114aaf 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -1,7 +1,7 @@
+ #!/usr/bin/env python
+ 
+-# Copyright (C) 2016 g10 Code GmbH
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2016-2017 g10 Code GmbH
++# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
+ # Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+ #
+ #    This library is free software; you can redistribute it and/or
+@@ -19,11 +19,18 @@
+ #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ 
+ from distutils.core import setup, Extension
++import argparse
+ import os, os.path, sys
+ import glob
++import re
+ import shutil
+ import subprocess
+ 
++# We parse a subset of the arguments.
++parser = argparse.ArgumentParser(add_help=False)
++parser.add_argument('--build-base', default='')
++options, _ = parser.parse_known_args()
++
+ # Out-of-tree build of the gpg bindings.
+ gpg_error_config = ["gpg-error-config"]
+ gpgme_config_flags = ["--thread=pthread"]
+@@ -31,6 +38,7 @@ gpgme_config = ["gpgme-config"] + gpgme_config_flags
+ gpgme_h = ""
+ include_dirs = [os.getcwd()]
+ library_dirs = []
++vpath_build = os.environ.get('srcdir', '.') != '.'
+ in_tree = False
+ extra_swig_opts = []
+ extra_macros = dict()
+@@ -133,6 +141,14 @@ if uname_s.startswith("MINGW32"):
+                library_dirs.append(os.path.join(tgt, item))
+                break
+ 
++def in_srcdir(name):
++    return os.path.join(os.environ.get("srcdir", ""), name)
++def in_build_base(name):
++    return os.path.join(options.build_base, name)
++def up_to_date(source, target):
++    return (os.path.exists(target)
++            and os.path.getmtime(source) <= os.path.getmtime(target))
++
+ # We build an Extension using SWIG, which generates a Python module.
+ # By default, the 'build_py' step is run before 'build_ext', and
+ # therefore the generated Python module is not copied into the build
+@@ -143,25 +159,60 @@ if uname_s.startswith("MINGW32"):
+ from distutils.command.build import build
+ class BuildExtFirstHack(build):
+ 
++    def _generate_gpgme_h(self, source_name, sink_name):
++        if up_to_date(source_name, sink_name):
++            return
++
++        deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
++                                 + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
++                                 re.S)
++        line_break = re.compile(';|\\$|\\x0c|^\s*#|{')
++
++        with open(sink_name, "w") as sink, open(source_name) as source:
++            text = ''
++            for line in source:
++                text += re.sub(' class ', ' _py_obsolete_class ', line)
++                if line_break.search(line):
++                    if not deprec_func.search(text):
++                        sink.write(text)
++                    text = ''
++            sink.write(text)
++
++    def _generate_errors_i(self, source_name, sink_name):
++        if up_to_date(source_name, sink_name):
++            return
++
++        filter_re = re.compile(r'GPG_ERR_[^ ]* =')
++        rewrite_re = re.compile(r' *(.*) = .*')
++
++        with open(sink_name, "w") as sink, open(source_name) as source:
++            for line in source:
++                if not filter_re.search(line):
++                    continue
++                sink.write(rewrite_re.sub(r'%constant long \1 = \1;'+'\n', line.strip()))
++
+     def _generate(self):
+         print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
+ 
+         # Cleanup gpgme.h from deprecated functions and typedefs.
+-        # Keep timestamp to avoid rebuild
+         if not os.path.exists(self.build_base):
+             os.makedirs(self.build_base)
+ 
+-        for src, dst in (
+-            (gpgme_h, os.path.join(self.build_base, "gpgme.h")),
+-            (gpg_error_h, os.path.join(self.build_base, "errors.i"))
+-        ):
+-            subprocess.check_call([sys.executable, "gpgme-h-clean.py", src],
+-                                  stdout=open(dst, "w"))
+-            shutil.copystat(src, dst)
++        self._generate_gpgme_h(gpgme_h, in_build_base("gpgme.h"))
++        self._generate_errors_i(gpg_error_h, in_build_base("errors.i"))
++
++        # Keep timestamp to avoid rebuild
++        for source, target in ((gpgme_h, in_build_base("gpgme.h")),
++                               (gpg_error_h, in_build_base("errors.i"))):
++            if not up_to_date(source, target):
++                shutil.copystat(source, target)
+ 
+         # Copy due to http://bugs.python.org/issue2624
+         # Avoid creating in srcdir
+-        shutil.copy2("gpgme.i", self.build_base)
++        for source, target in ((in_srcdir(n), in_build_base(n))
++                               for n in ('gpgme.i', 'helpers.c')):
++            if not up_to_date(source, target):
++                shutil.copy2(source, target)
+ 
+     def run(self):
+         self._generate()
+@@ -171,14 +222,18 @@ class BuildExtFirstHack(build):
+             os.makedirs(os.path.join(self.build_lib, "gpg"))
+ 
+         swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
+-        swig_opts.extend(['-I' + self.build_base, '-outdir', os.path.join(self.build_lib, 'gpg')])
++        swig_opts.extend(['-I' + self.build_base,
++                          '-I' + in_srcdir('.'),
++                          '-outdir', os.path.join(self.build_lib, 'gpg')])
++        if vpath_build:
++            include_dirs.append(in_srcdir('.'))
+         include_dirs.append(self.build_base)
+ 
+         self.run_command('build_ext')
+         build.run(self)
+ 
+ py3 = [] if sys.version_info.major < 3 else ['-py3']
+-swig_sources = ['helpers.c']
++swig_sources = [in_build_base('helpers.c')]
+ swig_opts = ['-threads'] + py3 + extra_swig_opts
+ swige = Extension("gpg._gpgme",
+                   sources = swig_sources,
diff --git a/debian/patches/0007-python-simplify-build-some-fixups.patch b/debian/patches/0007-python-simplify-build-some-fixups.patch
new file mode 100644
index 0000000..9e0ebe6
--- /dev/null
+++ b/debian/patches/0007-python-simplify-build-some-fixups.patch
@@ -0,0 +1,5970 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Wed, 5 Apr 2017 19:47:08 +0300
+Subject: python: simplify build, some fixups
+
+* lang/python/gpg/version.py.in: Rename to lang/python/version.py.in.
+configure.ac: Generate version.py.in in lang/python.
+* lang/python/MANIFEST.in: Include version.py explicitly.
+* lang/python/gpg: Rename to 'src'.
+* lang/python/Makefile.am: Do not copy source files, do not use absolute
+directories, support lib64 in uninstall, clean also dist directory, use
+symlink for gpg src.
+* lang/python/setup.py.in: Use builddir, copy sources into builddir,
+copy version.py into module.
+--
+
+Simplify build to symlink the gpg sources into builddir instead of
+copying. This requires handling of version.py as generated file.
+
+In addition apply some cleanups: Drop the absolution pathes, clean the
+dist directory as well, support lib64 for sitelib at uninstall.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 49195c487e6c923f7137f092b982e7d833d98de6)
+---
+ configure.ac                                  |    2 +-
+ lang/python/MANIFEST.in                       |    1 +
+ lang/python/Makefile.am                       |   38 +-
+ lang/python/gpg/__init__.py                   |  121 --
+ lang/python/gpg/callbacks.py                  |   49 -
+ lang/python/gpg/constants/__init__.py         |  142 ---
+ lang/python/gpg/constants/create.py           |   25 -
+ lang/python/gpg/constants/data/__init__.py    |    6 -
+ lang/python/gpg/constants/data/encoding.py    |   23 -
+ lang/python/gpg/constants/event.py            |   23 -
+ lang/python/gpg/constants/import.py           |   23 -
+ lang/python/gpg/constants/keylist/__init__.py |    6 -
+ lang/python/gpg/constants/keylist/mode.py     |   23 -
+ lang/python/gpg/constants/keysign.py          |   25 -
+ lang/python/gpg/constants/md.py               |   23 -
+ lang/python/gpg/constants/pk.py               |   23 -
+ lang/python/gpg/constants/protocol.py         |   23 -
+ lang/python/gpg/constants/sig/__init__.py     |    6 -
+ lang/python/gpg/constants/sig/mode.py         |   23 -
+ lang/python/gpg/constants/sig/notation.py     |   25 -
+ lang/python/gpg/constants/sigsum.py           |   23 -
+ lang/python/gpg/constants/status.py           |  124 --
+ lang/python/gpg/constants/tofu/__init__.py    |   24 -
+ lang/python/gpg/constants/tofu/policy.py      |   25 -
+ lang/python/gpg/constants/validity.py         |   23 -
+ lang/python/gpg/core.py                       | 1490 -------------------------
+ lang/python/gpg/errors.py                     |  128 ---
+ lang/python/gpg/results.py                    |  118 --
+ lang/python/gpg/util.py                       |   53 -
+ lang/python/gpg/version.py.in                 |   68 --
+ lang/python/setup.py.in                       |   23 +-
+ lang/python/src/__init__.py                   |  121 ++
+ lang/python/src/callbacks.py                  |   49 +
+ lang/python/src/constants/__init__.py         |  142 +++
+ lang/python/src/constants/create.py           |   25 +
+ lang/python/src/constants/data/__init__.py    |    6 +
+ lang/python/src/constants/data/encoding.py    |   23 +
+ lang/python/src/constants/event.py            |   23 +
+ lang/python/src/constants/import.py           |   23 +
+ lang/python/src/constants/keylist/__init__.py |    6 +
+ lang/python/src/constants/keylist/mode.py     |   23 +
+ lang/python/src/constants/keysign.py          |   25 +
+ lang/python/src/constants/md.py               |   23 +
+ lang/python/src/constants/pk.py               |   23 +
+ lang/python/src/constants/protocol.py         |   23 +
+ lang/python/src/constants/sig/__init__.py     |    6 +
+ lang/python/src/constants/sig/mode.py         |   23 +
+ lang/python/src/constants/sig/notation.py     |   25 +
+ lang/python/src/constants/sigsum.py           |   23 +
+ lang/python/src/constants/status.py           |  124 ++
+ lang/python/src/constants/tofu/__init__.py    |   24 +
+ lang/python/src/constants/tofu/policy.py      |   25 +
+ lang/python/src/constants/validity.py         |   23 +
+ lang/python/src/core.py                       | 1490 +++++++++++++++++++++++++
+ lang/python/src/errors.py                     |  128 +++
+ lang/python/src/results.py                    |  118 ++
+ lang/python/src/util.py                       |   53 +
+ lang/python/version.py.in                     |   68 ++
+ 58 files changed, 2689 insertions(+), 2705 deletions(-)
+ delete mode 100644 lang/python/gpg/__init__.py
+ delete mode 100644 lang/python/gpg/callbacks.py
+ delete mode 100644 lang/python/gpg/constants/__init__.py
+ delete mode 100644 lang/python/gpg/constants/create.py
+ delete mode 100644 lang/python/gpg/constants/data/__init__.py
+ delete mode 100644 lang/python/gpg/constants/data/encoding.py
+ delete mode 100644 lang/python/gpg/constants/event.py
+ delete mode 100644 lang/python/gpg/constants/import.py
+ delete mode 100644 lang/python/gpg/constants/keylist/__init__.py
+ delete mode 100644 lang/python/gpg/constants/keylist/mode.py
+ delete mode 100644 lang/python/gpg/constants/keysign.py
+ delete mode 100644 lang/python/gpg/constants/md.py
+ delete mode 100644 lang/python/gpg/constants/pk.py
+ delete mode 100644 lang/python/gpg/constants/protocol.py
+ delete mode 100644 lang/python/gpg/constants/sig/__init__.py
+ delete mode 100644 lang/python/gpg/constants/sig/mode.py
+ delete mode 100644 lang/python/gpg/constants/sig/notation.py
+ delete mode 100644 lang/python/gpg/constants/sigsum.py
+ delete mode 100644 lang/python/gpg/constants/status.py
+ delete mode 100644 lang/python/gpg/constants/tofu/__init__.py
+ delete mode 100644 lang/python/gpg/constants/tofu/policy.py
+ delete mode 100644 lang/python/gpg/constants/validity.py
+ delete mode 100644 lang/python/gpg/core.py
+ delete mode 100644 lang/python/gpg/errors.py
+ delete mode 100644 lang/python/gpg/results.py
+ delete mode 100644 lang/python/gpg/util.py
+ delete mode 100644 lang/python/gpg/version.py.in
+ create mode 100644 lang/python/src/__init__.py
+ create mode 100644 lang/python/src/callbacks.py
+ create mode 100644 lang/python/src/constants/__init__.py
+ create mode 100644 lang/python/src/constants/create.py
+ create mode 100644 lang/python/src/constants/data/__init__.py
+ create mode 100644 lang/python/src/constants/data/encoding.py
+ create mode 100644 lang/python/src/constants/event.py
+ create mode 100644 lang/python/src/constants/import.py
+ create mode 100644 lang/python/src/constants/keylist/__init__.py
+ create mode 100644 lang/python/src/constants/keylist/mode.py
+ create mode 100644 lang/python/src/constants/keysign.py
+ create mode 100644 lang/python/src/constants/md.py
+ create mode 100644 lang/python/src/constants/pk.py
+ create mode 100644 lang/python/src/constants/protocol.py
+ create mode 100644 lang/python/src/constants/sig/__init__.py
+ create mode 100644 lang/python/src/constants/sig/mode.py
+ create mode 100644 lang/python/src/constants/sig/notation.py
+ create mode 100644 lang/python/src/constants/sigsum.py
+ create mode 100644 lang/python/src/constants/status.py
+ create mode 100644 lang/python/src/constants/tofu/__init__.py
+ create mode 100644 lang/python/src/constants/tofu/policy.py
+ create mode 100644 lang/python/src/constants/validity.py
+ create mode 100644 lang/python/src/core.py
+ create mode 100644 lang/python/src/errors.py
+ create mode 100644 lang/python/src/results.py
+ create mode 100644 lang/python/src/util.py
+ create mode 100644 lang/python/version.py.in
+
+diff --git a/configure.ac b/configure.ac
+index 7ba07cc..e77cc23 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -878,7 +878,7 @@ AC_CONFIG_FILES([lang/Makefile lang/cl/Makefile lang/cl/gpgme.asd])
+ AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([lang/qt/doc/Doxyfile])])
+ AC_CONFIG_FILES(lang/qt/doc/Makefile)
+ AC_CONFIG_FILES([lang/python/Makefile
+-		 lang/python/gpg/version.py
++		 lang/python/version.py
+ 		 lang/python/tests/Makefile])
+ AC_CONFIG_FILES([lang/python/setup.py], [chmod a+x lang/python/setup.py])
+ AC_OUTPUT
+diff --git a/lang/python/MANIFEST.in b/lang/python/MANIFEST.in
+index ff38172..c34e84a 100644
+--- a/lang/python/MANIFEST.in
++++ b/lang/python/MANIFEST.in
+@@ -1,4 +1,5 @@
+ recursive-include examples *.py
+ include gpgme.i
+ include helpers.c helpers.h private.h
++include version.py
+ recursive-include gpg *.py
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index 42beeee..4ebd214 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -22,28 +22,19 @@ EXTRA_DIST = \
+ 	gpgme.i \
+ 	helpers.c helpers.h private.h \
+ 	examples \
+-	gpg
++	src
+ 
+ SUBDIRS = . tests
+ 
+-COPY_FILES_GPG = \
+-	$(srcdir)/gpg/callbacks.py \
+-	$(srcdir)/gpg/constants \
+-	$(srcdir)/gpg/core.py \
+-	$(srcdir)/gpg/errors.py \
+-	$(srcdir)/gpg/__init__.py \
+-	$(srcdir)/gpg/results.py \
+-	$(srcdir)/gpg/util.py
+-
+ .PHONY: prepare
+ prepare: copystamp
+ 
+ # For VPATH builds we need to copy some files because Python's
+ # distutils are not VPATH-aware.
+ copystamp:
+-	ln -sf "$(abs_top_srcdir)/src/data.h" .
+-	ln -sf "$(abs_top_builddir)/config.h" .
+-	if test $(srcdir) != . ; then cp -R $(COPY_FILES_GPG) gpg ; fi
++	ln -sf "$(top_srcdir)/src/data.h" .
++	ln -sf "$(top_builddir)/config.h" .
++	ln -sf "$(srcdir)/src" gpg
+ 	touch $@
+ 
+ all-local: copystamp
+@@ -51,7 +42,7 @@ all-local: copystamp
+ 	  PYTHON="$$1" ; shift ; \
+ 	  CFLAGS="$(CFLAGS)" \
+ 	  srcdir="$(srcdir)" \
+-	  abs_top_builddir="$(abs_top_builddir)" \
++	  top_builddir="$(top_builddir)" \
+ 	    $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
+ 	done
+ 
+@@ -59,7 +50,7 @@ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+ 	$(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
+ 	CFLAGS="$(CFLAGS)" \
+ 	srcdir="$(srcdir)" \
+-	abs_top_builddir="$(abs_top_builddir)" \
++	top_builddir="$(top_builddir)" \
+ 	  $(PYTHON) setup.py sdist --verbose --dist-dir=python$(PYTHON_VERSION)-gpg-dist \
+ 		--manifest=python$(PYTHON_VERSION)-gpg-dist/MANIFEST
+ 	gpg2 --detach-sign --armor python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz
+@@ -75,6 +66,7 @@ upload: python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz \
+ CLEANFILES = copystamp \
+ 	config.h \
+ 	data.h \
++	gpg \
+ 	files.txt \
+ 	install_files.txt
+ 
+@@ -84,22 +76,16 @@ CLEANFILES = copystamp \
+ # permissions.
+ clean-local:
+ 	rm -rf -- build
+-	if test $(srcdir) != . ; then \
+-	  find gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+-	  for FILE in $(COPY_FILES_GPG); do \
+-	    rm -rf -- gpg/$$(basename $$FILE) ; \
+-	  done \
+-	fi
+ 	for VERSION in $(PYTHON_VERSIONS); do \
+-	  find python$${VERSION}-gpg -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+-	  rm -rf -- python$${VERSION}-gpg ; \
++	  find python$${VERSION}-gpg* -type d ! -perm -200 -exec chmod u+w {} ';' ; \
++	  rm -rf -- python$${VERSION}-gpg* ; \
+ 	done
+ 
+ install-exec-local:
+ 	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+ 	  PYTHON="$$1" ; shift ; \
+ 	  srcdir="$(srcdir)" \
+-	  abs_top_builddir="$(abs_top_builddir)" \
++	  top_builddir="$(top_builddir)" \
+ 	  $$PYTHON setup.py \
+ 	  build \
+ 	  --build-base=python$${VERSION}-gpg \
+@@ -110,6 +96,6 @@ install-exec-local:
+ 
+ uninstall-local:
+ 	GV=$$(echo $(VERSION) | tr - _); for PV in $(PYTHON_VERSIONS); do \
+-	  rm -rf -- "$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg" \
+-"$(DESTDIR)$(prefix)/lib/python$$PV/site-packages/gpg-$$GV-py$$PV.egg-info" ; \
++	  rm -rf -- "$(DESTDIR)$(prefix)"/lib*/python$$PV/site-packages/gpg \
++"$(DESTDIR)$(prefix)"/lib*/python$$PV/site-packages/gpg-$$GV-py$$PV.egg-info ; \
+ 	done
+diff --git a/lang/python/gpg/__init__.py b/lang/python/gpg/__init__.py
+deleted file mode 100644
+index 385b17e..0000000
+--- a/lang/python/gpg/__init__.py
++++ /dev/null
+@@ -1,121 +0,0 @@
+-# Copyright (C) 2016 g10 Code GmbH
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-# This library 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.
+-#
+-# This library 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 library; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-"""gpg: GnuPG Interface for Python (GPGME bindings)
+-
+-Welcome to gpg, the GnuPG Interface for Python.
+-
+-The latest release of this package may be obtained from
+-https://www.gnupg.org
+-
+-FEATURES
+---------
+-
+- * Feature-rich, full implementation of the GPGME library.  Supports
+-   all GPGME features.  Callback functions may be written in pure
+-   Python.  Exceptions raised in callbacks are properly propagated.
+-
+- * Ability to sign, encrypt, decrypt, and verify data.
+-
+- * Ability to list keys, export and import keys, and manage the keyring.
+-
+- * Fully object-oriented with convenient classes and modules.
+-
+-QUICK EXAMPLE
+--------------
+-
+-    >>> import gpg
+-    >>> with gpg.Context() as c:
+-    >>> with gpg.Context() as c:
+-    ...     cipher, _, _ = c.encrypt("Hello world :)".encode(),
+-    ...                              passphrase="abc")
+-    ...     c.decrypt(cipher, passphrase="abc")
+-    ...
+-    (b'Hello world :)',
+-     <gpg.results.DecryptResult object at 0x7f5ab8121080>,
+-     <gpg.results.VerifyResult object at 0x7f5ab81219b0>)
+-
+-GENERAL OVERVIEW
+-----------------
+-
+-For those of you familiar with GPGME, you will be right at home here.
+-
+-The python gpg module is, for the most part, a direct interface to the C GPGME
+-library.  However, it is re-packaged in a more Pythonic way --
+-object-oriented with classes and modules.  Take a look at the classes
+-defined here -- they correspond directly to certain object types in GPGME
+-for C.  For instance, the following C code:
+-
+-gpgme_ctx_t context;
+-gpgme_new(&context);
+-...
+-gpgme_op_encrypt(context, recp, 1, plain, cipher);
+-
+-Translates into the following Python code:
+-
+-context = core.Context()
+-...
+-context.op_encrypt(recp, 1, plain, cipher)
+-
+-The Python module automatically does error-checking and raises Python
+-exception gpg.errors.GPGMEError when GPGME signals an error. getcode()
+-and getsource() of this exception return code and source of the error.
+-
+-IMPORTANT NOTE
+---------------
+-This documentation only covers a small subset of available GPGME functions and
+-methods.  Please consult the documentation for the C library
+-for comprehensive coverage.
+-
+-This library uses Python's reflection to automatically detect the methods
+-that are available for each class, and as such, most of those methods
+-do not appear explicitly anywhere. You can use dir() python built-in command
+-on an object to see what methods and fields it has but their meaning can
+-be found only in GPGME documentation.
+-
+-FOR MORE INFORMATION
+---------------------
+-GnuPG homepage: https://www.gnupg.org/
+-GPGME documentation: https://www.gnupg.org/documentation/manuals/gpgme/
+-
+-"""
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import core
+-from . import errors
+-from . import constants
+-from . import util
+-from . import callbacks
+-from . import version
+-from .core import Context
+-from .core import Data
+-
+-# Interface hygiene.
+-
+-# Drop the low-level gpgme that creeps in for some reason.
+-gpgme = None
+-del gpgme
+-
+-# This is a white-list of symbols.  Any other will alert pyflakes.
+-_ = [Context, Data, core, errors, constants, util, callbacks, version]
+-del _
+-
+-__all__ = ["Context", "Data",
+-           "core", "errors", "constants", "util", "callbacks", "version"]
+diff --git a/lang/python/gpg/callbacks.py b/lang/python/gpg/callbacks.py
+deleted file mode 100644
+index b25a9a7..0000000
+--- a/lang/python/gpg/callbacks.py
++++ /dev/null
+@@ -1,49 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from getpass import getpass
+-
+-def passphrase_stdin(hint, desc, prev_bad, hook=None):
+-    """This is a sample callback that will read a passphrase from
+-    the terminal.  The hook here, if present, will be used to describe
+-    why the passphrase is needed."""
+-    why = ''
+-    if hook != None:
+-        why = ' ' + hook
+-    if prev_bad:
+-        why += ' (again)'
+-    print("Please supply %s' password%s:" % (hint, why))
+-    return getpass()
+-
+-def progress_stdout(what, type, current, total, hook=None):
+-    print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\
+-          (what, type, current, total))
+-
+-def readcb_fh(count, hook):
+-    """A callback for data.  hook should be a Python file-like object."""
+-    if count:
+-        # Should return '' on EOF
+-        return hook.read(count)
+-    else:
+-        # Wants to rewind.
+-        if not hasattr(hook, 'seek'):
+-            return None
+-        hook.seek(0, 0)
+-        return None
+diff --git a/lang/python/gpg/constants/__init__.py b/lang/python/gpg/constants/__init__.py
+deleted file mode 100644
+index 484ffd2..0000000
+--- a/lang/python/gpg/constants/__init__.py
++++ /dev/null
+@@ -1,142 +0,0 @@
+-# Constants.
+-#
+-# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_', globals())
+-del util
+-
+-# For convenience, we import the modules here.
+-from . import data, keylist, sig, tofu # The subdirs.
+-from . import create, event, keysign, md, pk, protocol, sigsum, status, validity
+-
+-# A complication arises because 'import' is a reserved keyword.
+-# Import it as 'Import' instead.
+-globals()['Import'] = getattr(__import__('', globals(), locals(),
+-                                         [str('import')], 1), "import")
+-
+-__all__ = ['data', 'event', 'import', 'keysign', 'keylist', 'md', 'pk',
+-           'protocol', 'sig', 'sigsum', 'status', 'tofu', 'validity', 'create']
+-
+-# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
+-# implement gpg.Context.op_edit using gpgme_op_interact, so the
+-# callbacks will be called with string keywords instead of numeric
+-# status messages.  Code that is using these constants will continue
+-# to work.
+-
+-STATUS_ABORT = "ABORT"
+-STATUS_ALREADY_SIGNED = "ALREADY_SIGNED"
+-STATUS_ATTRIBUTE = "ATTRIBUTE"
+-STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
+-STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE"
+-STATUS_BADARMOR = "BADARMOR"
+-STATUS_BADMDC = "BADMDC"
+-STATUS_BADSIG = "BADSIG"
+-STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
+-STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
+-STATUS_BEGIN_SIGNING = "BEGIN_SIGNING"
+-STATUS_BEGIN_STREAM = "BEGIN_STREAM"
+-STATUS_CARDCTRL = "CARDCTRL"
+-STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED"
+-STATUS_DECRYPTION_INFO = "DECRYPTION_INFO"
+-STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY"
+-STATUS_DELETE_PROBLEM = "DELETE_PROBLEM"
+-STATUS_ENC_TO = "ENC_TO"
+-STATUS_END_DECRYPTION = "END_DECRYPTION"
+-STATUS_END_ENCRYPTION = "END_ENCRYPTION"
+-STATUS_END_STREAM = "END_STREAM"
+-STATUS_ENTER = "ENTER"
+-STATUS_ERRMDC = "ERRMDC"
+-STATUS_ERROR = "ERROR"
+-STATUS_ERRSIG = "ERRSIG"
+-STATUS_EXPKEYSIG = "EXPKEYSIG"
+-STATUS_EXPSIG = "EXPSIG"
+-STATUS_FAILURE = "FAILURE"
+-STATUS_FILE_DONE = "FILE_DONE"
+-STATUS_FILE_ERROR = "FILE_ERROR"
+-STATUS_FILE_START = "FILE_START"
+-STATUS_GET_BOOL = "GET_BOOL"
+-STATUS_GET_HIDDEN = "GET_HIDDEN"
+-STATUS_GET_LINE = "GET_LINE"
+-STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
+-STATUS_GOODMDC = "GOODMDC"
+-STATUS_GOODSIG = "GOODSIG"
+-STATUS_GOT_IT = "GOT_IT"
+-STATUS_IMPORT_OK = "IMPORT_OK"
+-STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM"
+-STATUS_IMPORT_RES = "IMPORT_RES"
+-STATUS_IMPORTED = "IMPORTED"
+-STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
+-STATUS_INV_RECP = "INV_RECP"
+-STATUS_INV_SGNR = "INV_SGNR"
+-STATUS_KEY_CONSIDERED = "KEY_CONSIDERED"
+-STATUS_KEY_CREATED = "KEY_CREATED"
+-STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED"
+-STATUS_KEYEXPIRED = "KEYEXPIRED"
+-STATUS_KEYREVOKED = "KEYREVOKED"
+-STATUS_LEAVE = "LEAVE"
+-STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
+-STATUS_MOUNTPOINT = "MOUNTPOINT"
+-STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE"
+-STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
+-STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
+-STATUS_NEWSIG = "NEWSIG"
+-STATUS_NO_PUBKEY = "NO_PUBKEY"
+-STATUS_NO_RECP = "NO_RECP"
+-STATUS_NO_SECKEY = "NO_SECKEY"
+-STATUS_NO_SGNR = "NO_SGNR"
+-STATUS_NODATA = "NODATA"
+-STATUS_NOTATION_DATA = "NOTATION_DATA"
+-STATUS_NOTATION_FLAGS = "NOTATION_FLAGS"
+-STATUS_NOTATION_NAME = "NOTATION_NAME"
+-STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
+-STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD"
+-STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
+-STATUS_PLAINTEXT = "PLAINTEXT"
+-STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
+-STATUS_POLICY_URL = "POLICY_URL"
+-STATUS_PROGRESS = "PROGRESS"
+-STATUS_REVKEYSIG = "REVKEYSIG"
+-STATUS_RSA_OR_IDEA = "RSA_OR_IDEA"
+-STATUS_SC_OP_FAILURE = "SC_OP_FAILURE"
+-STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS"
+-STATUS_SESSION_KEY = "SESSION_KEY"
+-STATUS_SHM_GET = "SHM_GET"
+-STATUS_SHM_GET_BOOL = "SHM_GET_BOOL"
+-STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
+-STATUS_SHM_INFO = "SHM_INFO"
+-STATUS_SIG_CREATED = "SIG_CREATED"
+-STATUS_SIG_ID = "SIG_ID"
+-STATUS_SIG_SUBPACKET = "SIG_SUBPACKET"
+-STATUS_SIGEXPIRED = "SIGEXPIRED"
+-STATUS_SUCCESS = "SUCCESS"
+-STATUS_TOFU_STATS = "TOFU_STATS"
+-STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG"
+-STATUS_TOFU_USER = "TOFU_USER"
+-STATUS_TRUNCATED = "TRUNCATED"
+-STATUS_TRUST_FULLY = "TRUST_FULLY"
+-STATUS_TRUST_MARGINAL = "TRUST_MARGINAL"
+-STATUS_TRUST_NEVER = "TRUST_NEVER"
+-STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE"
+-STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED"
+-STATUS_UNEXPECTED = "UNEXPECTED"
+-STATUS_USERID_HINT = "USERID_HINT"
+-STATUS_VALIDSIG = "VALIDSIG"
+diff --git a/lang/python/gpg/constants/create.py b/lang/python/gpg/constants/create.py
+deleted file mode 100644
+index 132e96d..0000000
+--- a/lang/python/gpg/constants/create.py
++++ /dev/null
+@@ -1,25 +0,0 @@
+-# Flags for key creation
+-#
+-# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_CREATE_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/data/__init__.py b/lang/python/gpg/constants/data/__init__.py
+deleted file mode 100644
+index 8274ab9..0000000
+--- a/lang/python/gpg/constants/data/__init__.py
++++ /dev/null
+@@ -1,6 +0,0 @@
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import encoding
+-__all__ = ['encoding']
+diff --git a/lang/python/gpg/constants/data/encoding.py b/lang/python/gpg/constants/data/encoding.py
+deleted file mode 100644
+index e76a22e..0000000
+--- a/lang/python/gpg/constants/data/encoding.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_DATA_ENCODING_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/event.py b/lang/python/gpg/constants/event.py
+deleted file mode 100644
+index 1b14d1d..0000000
+--- a/lang/python/gpg/constants/event.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_EVENT_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/import.py b/lang/python/gpg/constants/import.py
+deleted file mode 100644
+index 47c296c..0000000
+--- a/lang/python/gpg/constants/import.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_IMPORT_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/keylist/__init__.py b/lang/python/gpg/constants/keylist/__init__.py
+deleted file mode 100644
+index 2ce0edf..0000000
+--- a/lang/python/gpg/constants/keylist/__init__.py
++++ /dev/null
+@@ -1,6 +0,0 @@
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import mode
+-__all__ = ['mode']
+diff --git a/lang/python/gpg/constants/keylist/mode.py b/lang/python/gpg/constants/keylist/mode.py
+deleted file mode 100644
+index 39e1819..0000000
+--- a/lang/python/gpg/constants/keylist/mode.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_KEYLIST_MODE_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/keysign.py b/lang/python/gpg/constants/keysign.py
+deleted file mode 100644
+index fccdbc4..0000000
+--- a/lang/python/gpg/constants/keysign.py
++++ /dev/null
+@@ -1,25 +0,0 @@
+-# Flags for key signing
+-#
+-# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_KEYSIGN_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/md.py b/lang/python/gpg/constants/md.py
+deleted file mode 100644
+index f3e8bbd..0000000
+--- a/lang/python/gpg/constants/md.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_MD_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/pk.py b/lang/python/gpg/constants/pk.py
+deleted file mode 100644
+index 6bf2a21..0000000
+--- a/lang/python/gpg/constants/pk.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_PK_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/protocol.py b/lang/python/gpg/constants/protocol.py
+deleted file mode 100644
+index d086bbd..0000000
+--- a/lang/python/gpg/constants/protocol.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_PROTOCOL_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/sig/__init__.py b/lang/python/gpg/constants/sig/__init__.py
+deleted file mode 100644
+index 39d4e6e..0000000
+--- a/lang/python/gpg/constants/sig/__init__.py
++++ /dev/null
+@@ -1,6 +0,0 @@
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import mode, notation
+-__all__ = ['mode', 'notation']
+diff --git a/lang/python/gpg/constants/sig/mode.py b/lang/python/gpg/constants/sig/mode.py
+deleted file mode 100644
+index 0f4f0ef..0000000
+--- a/lang/python/gpg/constants/sig/mode.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_SIG_MODE_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/sig/notation.py b/lang/python/gpg/constants/sig/notation.py
+deleted file mode 100644
+index 9a79e01..0000000
+--- a/lang/python/gpg/constants/sig/notation.py
++++ /dev/null
+@@ -1,25 +0,0 @@
+-# Constants for signature notation data.
+-#
+-# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_SIG_NOTATION_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/sigsum.py b/lang/python/gpg/constants/sigsum.py
+deleted file mode 100644
+index 09ef9d7..0000000
+--- a/lang/python/gpg/constants/sigsum.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_SIGSUM_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/status.py b/lang/python/gpg/constants/status.py
+deleted file mode 100644
+index a0ad073..0000000
+--- a/lang/python/gpg/constants/status.py
++++ /dev/null
+@@ -1,124 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
+-# implement gpg.Context.op_edit using gpgme_op_interact, so the
+-# callbacks will be called with string keywords instead of numeric
+-# status messages.  Code that is using these constants will continue
+-# to work.
+-
+-ABORT = "ABORT"
+-ALREADY_SIGNED = "ALREADY_SIGNED"
+-ATTRIBUTE = "ATTRIBUTE"
+-BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
+-BAD_PASSPHRASE = "BAD_PASSPHRASE"
+-BADARMOR = "BADARMOR"
+-BADMDC = "BADMDC"
+-BADSIG = "BADSIG"
+-BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
+-BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
+-BEGIN_SIGNING = "BEGIN_SIGNING"
+-BEGIN_STREAM = "BEGIN_STREAM"
+-CARDCTRL = "CARDCTRL"
+-DECRYPTION_FAILED = "DECRYPTION_FAILED"
+-DECRYPTION_INFO = "DECRYPTION_INFO"
+-DECRYPTION_OKAY = "DECRYPTION_OKAY"
+-DELETE_PROBLEM = "DELETE_PROBLEM"
+-ENC_TO = "ENC_TO"
+-END_DECRYPTION = "END_DECRYPTION"
+-END_ENCRYPTION = "END_ENCRYPTION"
+-END_STREAM = "END_STREAM"
+-ENTER = "ENTER"
+-ERRMDC = "ERRMDC"
+-ERROR = "ERROR"
+-ERRSIG = "ERRSIG"
+-EXPKEYSIG = "EXPKEYSIG"
+-EXPSIG = "EXPSIG"
+-FAILURE = "FAILURE"
+-FILE_DONE = "FILE_DONE"
+-FILE_ERROR = "FILE_ERROR"
+-FILE_START = "FILE_START"
+-GET_BOOL = "GET_BOOL"
+-GET_HIDDEN = "GET_HIDDEN"
+-GET_LINE = "GET_LINE"
+-GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
+-GOODMDC = "GOODMDC"
+-GOODSIG = "GOODSIG"
+-GOT_IT = "GOT_IT"
+-IMPORT_OK = "IMPORT_OK"
+-IMPORT_PROBLEM = "IMPORT_PROBLEM"
+-IMPORT_RES = "IMPORT_RES"
+-IMPORTED = "IMPORTED"
+-INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
+-INV_RECP = "INV_RECP"
+-INV_SGNR = "INV_SGNR"
+-KEY_CONSIDERED = "KEY_CONSIDERED"
+-KEY_CREATED = "KEY_CREATED"
+-KEY_NOT_CREATED = "KEY_NOT_CREATED"
+-KEYEXPIRED = "KEYEXPIRED"
+-KEYREVOKED = "KEYREVOKED"
+-LEAVE = "LEAVE"
+-MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
+-MOUNTPOINT = "MOUNTPOINT"
+-NEED_PASSPHRASE = "NEED_PASSPHRASE"
+-NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
+-NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
+-NEWSIG = "NEWSIG"
+-NO_PUBKEY = "NO_PUBKEY"
+-NO_RECP = "NO_RECP"
+-NO_SECKEY = "NO_SECKEY"
+-NO_SGNR = "NO_SGNR"
+-NODATA = "NODATA"
+-NOTATION_DATA = "NOTATION_DATA"
+-NOTATION_FLAGS = "NOTATION_FLAGS"
+-NOTATION_NAME = "NOTATION_NAME"
+-PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
+-PKA_TRUST_BAD = "PKA_TRUST_BAD"
+-PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
+-PLAINTEXT = "PLAINTEXT"
+-PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
+-POLICY_URL = "POLICY_URL"
+-PROGRESS = "PROGRESS"
+-REVKEYSIG = "REVKEYSIG"
+-RSA_OR_IDEA = "RSA_OR_IDEA"
+-SC_OP_FAILURE = "SC_OP_FAILURE"
+-SC_OP_SUCCESS = "SC_OP_SUCCESS"
+-SESSION_KEY = "SESSION_KEY"
+-SHM_GET = "SHM_GET"
+-SHM_GET_BOOL = "SHM_GET_BOOL"
+-SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
+-SHM_INFO = "SHM_INFO"
+-SIG_CREATED = "SIG_CREATED"
+-SIG_ID = "SIG_ID"
+-SIG_SUBPACKET = "SIG_SUBPACKET"
+-SIGEXPIRED = "SIGEXPIRED"
+-SUCCESS = "SUCCESS"
+-TOFU_STATS = "TOFU_STATS"
+-TOFU_STATS_LONG = "TOFU_STATS_LONG"
+-TOFU_USER = "TOFU_USER"
+-TRUNCATED = "TRUNCATED"
+-TRUST_FULLY = "TRUST_FULLY"
+-TRUST_MARGINAL = "TRUST_MARGINAL"
+-TRUST_NEVER = "TRUST_NEVER"
+-TRUST_ULTIMATE = "TRUST_ULTIMATE"
+-TRUST_UNDEFINED = "TRUST_UNDEFINED"
+-UNEXPECTED = "UNEXPECTED"
+-USERID_HINT = "USERID_HINT"
+-VALIDSIG = "VALIDSIG"
+diff --git a/lang/python/gpg/constants/tofu/__init__.py b/lang/python/gpg/constants/tofu/__init__.py
+deleted file mode 100644
+index 819a58b..0000000
+--- a/lang/python/gpg/constants/tofu/__init__.py
++++ /dev/null
+@@ -1,24 +0,0 @@
+-# TOFU
+-#
+-# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import policy
+-__all__ = ['policy']
+diff --git a/lang/python/gpg/constants/tofu/policy.py b/lang/python/gpg/constants/tofu/policy.py
+deleted file mode 100644
+index 5a61f06..0000000
+--- a/lang/python/gpg/constants/tofu/policy.py
++++ /dev/null
+@@ -1,25 +0,0 @@
+-# TOFU policies
+-#
+-# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_TOFU_POLICY_', globals())
+-del util
+diff --git a/lang/python/gpg/constants/validity.py b/lang/python/gpg/constants/validity.py
+deleted file mode 100644
+index d3c5345..0000000
+--- a/lang/python/gpg/constants/validity.py
++++ /dev/null
+@@ -1,23 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from gpg import util
+-util.process_constants('GPGME_VALIDITY_', globals())
+-del util
+diff --git a/lang/python/gpg/core.py b/lang/python/gpg/core.py
+deleted file mode 100644
+index 632f4ca..0000000
+--- a/lang/python/gpg/core.py
++++ /dev/null
+@@ -1,1490 +0,0 @@
+-# Copyright (C) 2016-2017 g10 Code GmbH
+-# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-"""Core functionality
+-
+-Core functionality of GPGME wrapped in a object-oriented fashion.
+-Provides the 'Context' class for performing cryptographic operations,
+-and the 'Data' class describing buffers of data.
+-
+-"""
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-import re
+-import os
+-import warnings
+-import weakref
+-from . import gpgme
+-from .errors import errorcheck, GPGMEError
+-from . import constants
+-from . import errors
+-from . import util
+-
+-class GpgmeWrapper(object):
+-    """Base wrapper class
+-
+-    Not to be instantiated directly.
+-
+-    """
+-
+-    def __init__(self, wrapped):
+-        self._callback_excinfo = None
+-        self.wrapped = wrapped
+-
+-    def __repr__(self):
+-        return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(),
+-                                  self.wrapped)
+-
+-    def __str__(self):
+-        acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
+-        flags = [f for f in self._boolean_properties if getattr(self, f)]
+-        if flags:
+-            acc.append('({})'.format(' '.join(flags)))
+-
+-        return '<{}>'.format(' '.join(acc))
+-
+-    def __hash__(self):
+-        return hash(repr(self.wrapped))
+-
+-    def __eq__(self, other):
+-        if other == None:
+-            return False
+-        else:
+-            return repr(self.wrapped) == repr(other.wrapped)
+-
+-    @property
+-    def _ctype(self):
+-        """The name of the c type wrapped by this class
+-
+-        Must be set by child classes.
+-
+-        """
+-        raise NotImplementedError()
+-
+-    @property
+-    def _cprefix(self):
+-        """The common prefix of c functions wrapped by this class
+-
+-        Must be set by child classes.
+-
+-        """
+-        raise NotImplementedError()
+-
+-    def _errorcheck(self, name):
+-        """Must be implemented by child classes.
+-
+-        This function must return a trueish value for all c functions
+-        returning gpgme_error_t."""
+-        raise NotImplementedError()
+-
+-    """The set of all boolean properties"""
+-    _boolean_properties = set()
+-
+-    def __wrap_boolean_property(self, key, do_set=False, value=None):
+-        get_func = getattr(gpgme,
+-                           "{}get_{}".format(self._cprefix, key))
+-        set_func = getattr(gpgme,
+-                           "{}set_{}".format(self._cprefix, key))
+-        def get(slf):
+-            return bool(get_func(slf.wrapped))
+-        def set_(slf, value):
+-            set_func(slf.wrapped, bool(value))
+-
+-        p = property(get, set_, doc="{} flag".format(key))
+-        setattr(self.__class__, key, p)
+-
+-        if do_set:
+-            set_(self, bool(value))
+-        else:
+-            return get(self)
+-
+-    _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)')
+-    def __getattr__(self, key):
+-        """On-the-fly generation of wrapper methods and properties"""
+-        if key[0] == '_' or self._cprefix == None:
+-            return None
+-
+-        if key in self._boolean_properties:
+-            return self.__wrap_boolean_property(key)
+-
+-        name = self._cprefix + key
+-        func = getattr(gpgme, name)
+-
+-        if self._errorcheck(name):
+-            def _funcwrap(slf, *args):
+-                result = func(slf.wrapped, *args)
+-                if slf._callback_excinfo:
+-                    gpgme.gpg_raise_callback_exception(slf)
+-                return errorcheck(result, "Invocation of " + name)
+-        else:
+-            def _funcwrap(slf, *args):
+-                result = func(slf.wrapped, *args)
+-                if slf._callback_excinfo:
+-                    gpgme.gpg_raise_callback_exception(slf)
+-                return result
+-
+-        doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__"))
+-        _funcwrap.__doc__ = doc
+-
+-        # Monkey-patch the class.
+-        setattr(self.__class__, key, _funcwrap)
+-
+-        # Bind the method to 'self'.
+-        def wrapper(*args):
+-            return _funcwrap(self, *args)
+-        wrapper.__doc__ = doc
+-
+-        return wrapper
+-
+-    def __setattr__(self, key, value):
+-        """On-the-fly generation of properties"""
+-        if key in self._boolean_properties:
+-            self.__wrap_boolean_property(key, True, value)
+-        else:
+-            super(GpgmeWrapper, self).__setattr__(key, value)
+-
+-class Context(GpgmeWrapper):
+-    """Context for cryptographic operations
+-
+-    All cryptographic operations in GPGME are performed within a
+-    context, which contains the internal state of the operation as
+-    well as configuration parameters.  By using several contexts you
+-    can run several cryptographic operations in parallel, with
+-    different configuration.
+-
+-    Access to a context must be synchronized.
+-
+-    """
+-
+-    def __init__(self, armor=False, textmode=False, offline=False,
+-                 signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
+-                 protocol=constants.PROTOCOL_OpenPGP,
+-                 wrapped=None, home_dir=None):
+-        """Construct a context object
+-
+-        Keyword arguments:
+-        armor		-- enable ASCII armoring (default False)
+-        textmode	-- enable canonical text mode (default False)
+-        offline		-- do not contact external key sources (default False)
+-        signers		-- list of keys used for signing (default [])
+-        pinentry_mode	-- pinentry mode (default PINENTRY_MODE_DEFAULT)
+-        protocol	-- protocol to use (default PROTOCOL_OpenPGP)
+-        home_dir        -- state directory (default is the engine default)
+-
+-        """
+-        if wrapped:
+-            self.own = False
+-        else:
+-            tmp = gpgme.new_gpgme_ctx_t_p()
+-            errorcheck(gpgme.gpgme_new(tmp))
+-            wrapped = gpgme.gpgme_ctx_t_p_value(tmp)
+-            gpgme.delete_gpgme_ctx_t_p(tmp)
+-            self.own = True
+-        super(Context, self).__init__(wrapped)
+-        self.armor = armor
+-        self.textmode = textmode
+-        self.offline = offline
+-        self.signers = signers
+-        self.pinentry_mode = pinentry_mode
+-        self.protocol = protocol
+-        self.home_dir = home_dir
+-
+-    def __repr__(self):
+-        return (
+-            "Context(armor={0.armor}, "
+-            "textmode={0.textmode}, offline={0.offline}, "
+-            "signers={0.signers}, pinentry_mode={0.pinentry_mode}, "
+-            "protocol={0.protocol}, home_dir={0.home_dir}"
+-            ")").format(self)
+-
+-    def encrypt(self, plaintext, recipients=[], sign=True, sink=None,
+-                passphrase=None, always_trust=False, add_encrypt_to=False,
+-                prepare=False, expect_sign=False, compress=True):
+-        """Encrypt data
+-
+-        Encrypt the given plaintext for the given recipients.  If the
+-        list of recipients is empty, the data is encrypted
+-        symmetrically with a passphrase.
+-
+-        The passphrase can be given as parameter, using a callback
+-        registered at the context, or out-of-band via pinentry.
+-
+-        Keyword arguments:
+-        recipients	-- list of keys to encrypt to
+-        sign		-- sign plaintext (default True)
+-        sink		-- write result to sink instead of returning it
+-        passphrase	-- for symmetric encryption
+-        always_trust	-- always trust the keys (default False)
+-        add_encrypt_to	-- encrypt to configured additional keys (default False)
+-        prepare		-- (ui) prepare for encryption (default False)
+-        expect_sign	-- (ui) prepare for signing (default False)
+-        compress	-- compress plaintext (default True)
+-
+-        Returns:
+-        ciphertext	-- the encrypted data (or None if sink is given)
+-        result		-- additional information about the encryption
+-        sign_result	-- additional information about the signature(s)
+-
+-        Raises:
+-        InvalidRecipients -- if encryption using a particular key failed
+-        InvalidSigners	-- if signing using a particular key failed
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        ciphertext = sink if sink else Data()
+-        flags = 0
+-        flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST
+-        flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO
+-        flags |= prepare * constants.ENCRYPT_PREPARE
+-        flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN
+-        flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS
+-
+-        if passphrase != None:
+-            old_pinentry_mode = self.pinentry_mode
+-            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
+-            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
+-            def passphrase_cb(hint, desc, prev_bad, hook=None):
+-                return passphrase
+-            self.set_passphrase_cb(passphrase_cb)
+-
+-        try:
+-            if sign:
+-                self.op_encrypt_sign(recipients, flags, plaintext, ciphertext)
+-            else:
+-                self.op_encrypt(recipients, flags, plaintext, ciphertext)
+-        except errors.GPGMEError as e:
+-            if e.getcode() == errors.UNUSABLE_PUBKEY:
+-                result = self.op_encrypt_result()
+-                if result.invalid_recipients:
+-                    raise errors.InvalidRecipients(result.invalid_recipients)
+-            if e.getcode() == errors.UNUSABLE_SECKEY:
+-                sig_result = self.op_sign_result()
+-                if sig_result.invalid_signers:
+-                    raise errors.InvalidSigners(sig_result.invalid_signers)
+-            raise
+-        finally:
+-            if passphrase != None:
+-                self.pinentry_mode = old_pinentry_mode
+-                if old_passphrase_cb:
+-                    self.set_passphrase_cb(*old_passphrase_cb[1:])
+-
+-        result = self.op_encrypt_result()
+-        assert not result.invalid_recipients
+-        sig_result = self.op_sign_result() if sign else None
+-        assert not sig_result or not sig_result.invalid_signers
+-
+-        cipherbytes = None
+-        if not sink:
+-            ciphertext.seek(0, os.SEEK_SET)
+-            cipherbytes = ciphertext.read()
+-        return cipherbytes, result, sig_result
+-
+-    def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True):
+-        """Decrypt data
+-
+-        Decrypt the given ciphertext and verify any signatures.  If
+-        VERIFY is an iterable of keys, the ciphertext must be signed
+-        by all those keys, otherwise an error is raised.
+-
+-        If the ciphertext is symmetrically encrypted using a
+-        passphrase, that passphrase can be given as parameter, using a
+-        callback registered at the context, or out-of-band via
+-        pinentry.
+-
+-        Keyword arguments:
+-        sink		-- write result to sink instead of returning it
+-        passphrase	-- for symmetric decryption
+-        verify		-- check signatures (default True)
+-
+-        Returns:
+-        plaintext	-- the decrypted data (or None if sink is given)
+-        result		-- additional information about the decryption
+-        verify_result	-- additional information about the signature(s)
+-
+-        Raises:
+-        UnsupportedAlgorithm -- if an unsupported algorithm was used
+-        BadSignatures	-- if a bad signature is encountered
+-        MissingSignatures -- if expected signatures are missing or bad
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        plaintext = sink if sink else Data()
+-
+-        if passphrase != None:
+-            old_pinentry_mode = self.pinentry_mode
+-            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
+-            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
+-            def passphrase_cb(hint, desc, prev_bad, hook=None):
+-                return passphrase
+-            self.set_passphrase_cb(passphrase_cb)
+-
+-        try:
+-            if verify:
+-                self.op_decrypt_verify(ciphertext, plaintext)
+-            else:
+-                self.op_decrypt(ciphertext, plaintext)
+-        finally:
+-            if passphrase != None:
+-                self.pinentry_mode = old_pinentry_mode
+-                if old_passphrase_cb:
+-                    self.set_passphrase_cb(*old_passphrase_cb[1:])
+-
+-        result = self.op_decrypt_result()
+-        verify_result = self.op_verify_result() if verify else None
+-        if result.unsupported_algorithm:
+-            raise errors.UnsupportedAlgorithm(result.unsupported_algorithm)
+-
+-        if verify:
+-            if any(s.status != errors.NO_ERROR
+-                   for s in verify_result.signatures):
+-                raise errors.BadSignatures(verify_result)
+-
+-        if verify and verify != True:
+-            missing = list()
+-            for key in verify:
+-                ok = False
+-                for subkey in key.subkeys:
+-                    for sig in verify_result.signatures:
+-                        if sig.summary & constants.SIGSUM_VALID == 0:
+-                            continue
+-                        if subkey.can_sign and subkey.fpr == sig.fpr:
+-                            ok = True
+-                            break
+-                    if ok:
+-                        break
+-                if not ok:
+-                    missing.append(key)
+-            if missing:
+-                raise errors.MissingSignatures(verify_result, missing)
+-
+-        plainbytes = None
+-        if not sink:
+-            plaintext.seek(0, os.SEEK_SET)
+-            plainbytes = plaintext.read()
+-        return plainbytes, result, verify_result
+-
+-    def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL):
+-        """Sign data
+-
+-        Sign the given data with either the configured default local
+-        key, or the 'signers' keys of this context.
+-
+-        Keyword arguments:
+-        mode		-- signature mode (default: normal, see below)
+-        sink		-- write result to sink instead of returning it
+-
+-        Returns:
+-        either
+-          signed_data	-- encoded data and signature (normal mode)
+-          signature	-- only the signature data (detached mode)
+-          cleartext	-- data and signature as text (cleartext mode)
+-            (or None if sink is given)
+-        result		-- additional information about the signature(s)
+-
+-        Raises:
+-        InvalidSigners	-- if signing using a particular key failed
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        signeddata = sink if sink else Data()
+-
+-        try:
+-            self.op_sign(data, signeddata, mode)
+-        except errors.GPGMEError as e:
+-            if e.getcode() == errors.UNUSABLE_SECKEY:
+-                result = self.op_sign_result()
+-                if result.invalid_signers:
+-                    raise errors.InvalidSigners(result.invalid_signers)
+-            raise
+-
+-        result = self.op_sign_result()
+-        assert not result.invalid_signers
+-
+-        signedbytes = None
+-        if not sink:
+-            signeddata.seek(0, os.SEEK_SET)
+-            signedbytes = signeddata.read()
+-        return signedbytes, result
+-
+-    def verify(self, signed_data, signature=None, sink=None, verify=[]):
+-        """Verify signatures
+-
+-        Verify signatures over data.  If VERIFY is an iterable of
+-        keys, the ciphertext must be signed by all those keys,
+-        otherwise an error is raised.
+-
+-        Keyword arguments:
+-        signature	-- detached signature data
+-        sink		-- write result to sink instead of returning it
+-
+-        Returns:
+-        data		-- the plain data
+-            (or None if sink is given, or we verified a detached signature)
+-        result		-- additional information about the signature(s)
+-
+-        Raises:
+-        BadSignatures	-- if a bad signature is encountered
+-        MissingSignatures -- if expected signatures are missing or bad
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        if signature:
+-            # Detached signature, we don't return the plain text.
+-            data = None
+-        else:
+-            data = sink if sink else Data()
+-
+-        if signature:
+-            self.op_verify(signature, signed_data, None)
+-        else:
+-            self.op_verify(signed_data, None, data)
+-
+-        result = self.op_verify_result()
+-        if any(s.status != errors.NO_ERROR for s in result.signatures):
+-            raise errors.BadSignatures(result)
+-
+-        missing = list()
+-        for key in verify:
+-            ok = False
+-            for subkey in key.subkeys:
+-                for sig in result.signatures:
+-                    if sig.summary & constants.SIGSUM_VALID == 0:
+-                        continue
+-                    if subkey.can_sign and subkey.fpr == sig.fpr:
+-                        ok = True
+-                        break
+-                if ok:
+-                    break
+-            if not ok:
+-                missing.append(key)
+-        if missing:
+-            raise errors.MissingSignatures(result, missing)
+-
+-        plainbytes = None
+-        if data and not sink:
+-            data.seek(0, os.SEEK_SET)
+-            plainbytes = data.read()
+-        return plainbytes, result
+-
+-    def keylist(self, pattern=None, secret=False,
+-                mode=constants.keylist.mode.LOCAL,
+-                source=None):
+-        """List keys
+-
+-        Keyword arguments:
+-        pattern	-- return keys matching pattern (default: all keys)
+-        secret	-- return only secret keys (default: False)
+-        mode    -- keylist mode (default: list local keys)
+-        source  -- read keys from source instead from the keyring
+-                       (all other options are ignored in this case)
+-
+-        Returns:
+-                -- an iterator returning key objects
+-
+-        Raises:
+-        GPGMEError	-- as signaled by the underlying library
+-        """
+-        if not source:
+-            self.set_keylist_mode(mode)
+-            self.op_keylist_start(pattern, secret)
+-        else:
+-            # Automatic wrapping of SOURCE is not possible here,
+-            # because the object must not be deallocated until the
+-            # iteration over the results ends.
+-            if not isinstance(source, Data):
+-                source = Data(file=source)
+-            self.op_keylist_from_data_start(source, 0)
+-
+-        key = self.op_keylist_next()
+-        while key:
+-            yield key
+-            key = self.op_keylist_next()
+-        self.op_keylist_end()
+-
+-    def create_key(self, userid, algorithm=None, expires_in=0, expires=True,
+-                   sign=False, encrypt=False, certify=False, authenticate=False,
+-                   passphrase=None, force=False):
+-        """Create a primary key
+-
+-        Create a primary key for the user id USERID.
+-
+-        ALGORITHM may be used to specify the public key encryption
+-        algorithm for the new key.  By default, a reasonable default
+-        is chosen.  You may use "future-default" to select an
+-        algorithm that will be the default in a future implementation
+-        of the engine.  ALGORITHM may be a string like "rsa", or
+-        "rsa2048" to explicitly request an algorithm and a key size.
+-
+-        EXPIRES_IN specifies the expiration time of the key in number
+-        of seconds since the keys creation.  By default, a reasonable
+-        expiration time is chosen.  If you want to create a key that
+-        does not expire, use the keyword argument EXPIRES.
+-
+-        SIGN, ENCRYPT, CERTIFY, and AUTHENTICATE can be used to
+-        request the capabilities of the new key.  If you don't request
+-        any, a reasonable set of capabilities is selected, and in case
+-        of OpenPGP, a subkey with a reasonable set of capabilities is
+-        created.
+-
+-        If PASSPHRASE is None (the default), then the key will not be
+-        protected with a passphrase.  If PASSPHRASE is a string, it
+-        will be used to protect the key.  If PASSPHRASE is True, the
+-        passphrase must be supplied using a passphrase callback or
+-        out-of-band with a pinentry.
+-
+-        Keyword arguments:
+-        algorithm    -- public key algorithm, see above (default: reasonable)
+-        expires_in   -- expiration time in seconds (default: reasonable)
+-        expires      -- whether or not the key should expire (default: True)
+-        sign         -- request the signing capability (see above)
+-        encrypt      -- request the encryption capability (see above)
+-        certify      -- request the certification capability (see above)
+-        authenticate -- request the authentication capability (see above)
+-        passphrase   -- protect the key with a passphrase (default: no passphrase)
+-        force        -- force key creation even if a key with the same userid exists
+-                                                          (default: False)
+-
+-        Returns:
+-                     -- an object describing the result of the key creation
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        if util.is_a_string(passphrase):
+-            old_pinentry_mode = self.pinentry_mode
+-            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
+-            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
+-            def passphrase_cb(hint, desc, prev_bad, hook=None):
+-                return passphrase
+-            self.set_passphrase_cb(passphrase_cb)
+-
+-        try:
+-            self.op_createkey(userid, algorithm,
+-                              0, # reserved
+-                              expires_in,
+-                              None, # extrakey
+-                              ((constants.create.SIGN if sign else 0)
+-                               | (constants.create.ENCR if encrypt else 0)
+-                               | (constants.create.CERT if certify else 0)
+-                               | (constants.create.AUTH if authenticate else 0)
+-                               | (constants.create.NOPASSWD if passphrase == None else 0)
+-                               | (0 if expires else constants.create.NOEXPIRE)
+-                               | (constants.create.FORCE if force else 0)))
+-        finally:
+-            if util.is_a_string(passphrase):
+-                self.pinentry_mode = old_pinentry_mode
+-                if old_passphrase_cb:
+-                    self.set_passphrase_cb(*old_passphrase_cb[1:])
+-
+-        return self.op_genkey_result()
+-
+-    def create_subkey(self, key, algorithm=None, expires_in=0, expires=True,
+-                      sign=False, encrypt=False, authenticate=False, passphrase=None):
+-        """Create a subkey
+-
+-        Create a subkey for the given KEY.  As subkeys are a concept
+-        of OpenPGP, calling this is only valid for the OpenPGP
+-        protocol.
+-
+-        ALGORITHM may be used to specify the public key encryption
+-        algorithm for the new subkey.  By default, a reasonable
+-        default is chosen.  You may use "future-default" to select an
+-        algorithm that will be the default in a future implementation
+-        of the engine.  ALGORITHM may be a string like "rsa", or
+-        "rsa2048" to explicitly request an algorithm and a key size.
+-
+-        EXPIRES_IN specifies the expiration time of the subkey in
+-        number of seconds since the subkeys creation.  By default, a
+-        reasonable expiration time is chosen.  If you want to create a
+-        subkey that does not expire, use the keyword argument EXPIRES.
+-
+-        SIGN, ENCRYPT, and AUTHENTICATE can be used to request the
+-        capabilities of the new subkey.  If you don't request any, an
+-        encryption subkey is generated.
+-
+-        If PASSPHRASE is None (the default), then the subkey will not
+-        be protected with a passphrase.  If PASSPHRASE is a string, it
+-        will be used to protect the subkey.  If PASSPHRASE is True,
+-        the passphrase must be supplied using a passphrase callback or
+-        out-of-band with a pinentry.
+-
+-        Keyword arguments:
+-        algorithm    -- public key algorithm, see above (default: reasonable)
+-        expires_in   -- expiration time in seconds (default: reasonable)
+-        expires      -- whether or not the subkey should expire (default: True)
+-        sign         -- request the signing capability (see above)
+-        encrypt      -- request the encryption capability (see above)
+-        authenticate -- request the authentication capability (see above)
+-        passphrase   -- protect the subkey with a passphrase (default: no passphrase)
+-
+-        Returns:
+-                     -- an object describing the result of the subkey creation
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        if util.is_a_string(passphrase):
+-            old_pinentry_mode = self.pinentry_mode
+-            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
+-            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
+-            def passphrase_cb(hint, desc, prev_bad, hook=None):
+-                return passphrase
+-            self.set_passphrase_cb(passphrase_cb)
+-
+-        try:
+-            self.op_createsubkey(key, algorithm,
+-                                 0, # reserved
+-                                 expires_in,
+-                                 ((constants.create.SIGN if sign else 0)
+-                                  | (constants.create.ENCR if encrypt else 0)
+-                                  | (constants.create.AUTH if authenticate else 0)
+-                                  | (constants.create.NOPASSWD
+-                                     if passphrase == None else 0)
+-                                  | (0 if expires else constants.create.NOEXPIRE)))
+-        finally:
+-            if util.is_a_string(passphrase):
+-                self.pinentry_mode = old_pinentry_mode
+-                if old_passphrase_cb:
+-                    self.set_passphrase_cb(*old_passphrase_cb[1:])
+-
+-        return self.op_genkey_result()
+-
+-    def key_add_uid(self, key, uid):
+-        """Add a UID
+-
+-        Add the uid UID to the given KEY.  Calling this function is
+-        only valid for the OpenPGP protocol.
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        self.op_adduid(key, uid, 0)
+-
+-    def key_revoke_uid(self, key, uid):
+-        """Revoke a UID
+-
+-        Revoke the uid UID from the given KEY.  Calling this function
+-        is only valid for the OpenPGP protocol.
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        self.op_revuid(key, uid, 0)
+-
+-    def key_sign(self, key, uids=None, expires_in=False, local=False):
+-        """Sign a key
+-
+-        Sign a key with the current set of signing keys.  Calling this
+-        function is only valid for the OpenPGP protocol.
+-
+-        If UIDS is None (the default), then all UIDs are signed.  If
+-        it is a string, then only the matching UID is signed.  If it
+-        is a list of strings, then all matching UIDs are signed.  Note
+-        that a case-sensitive exact string comparison is done.
+-
+-        EXPIRES_IN specifies the expiration time of the signature in
+-        seconds.  If EXPIRES_IN is False, the signature does not
+-        expire.
+-
+-        Keyword arguments:
+-        uids         -- user ids to sign, see above (default: sign all)
+-        expires_in   -- validity period of the signature in seconds
+-                                               (default: do not expire)
+-        local        -- create a local, non-exportable signature
+-                                               (default: False)
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        flags = 0
+-        if uids == None or util.is_a_string(uids):
+-            pass#through unchanged
+-        else:
+-            flags |= constants.keysign.LFSEP
+-            uids = "\n".join(uids)
+-
+-        if not expires_in:
+-            flags |= constants.keysign.NOEXPIRE
+-
+-        if local:
+-            flags |= constants.keysign.LOCAL
+-
+-        self.op_keysign(key, uids, expires_in, flags)
+-
+-    def key_tofu_policy(self, key, policy):
+-        """Set a keys' TOFU policy
+-
+-        Set the TOFU policy associated with KEY to POLICY.  Calling
+-        this function is only valid for the OpenPGP protocol.
+-
+-        Raises:
+-        GPGMEError   -- as signaled by the underlying library
+-
+-        """
+-        self.op_tofu_policy(key, policy)
+-
+-    def assuan_transact(self, command,
+-                        data_cb=None, inquire_cb=None, status_cb=None):
+-        """Issue a raw assuan command
+-
+-        This function can be used to issue a raw assuan command to the
+-        engine.
+-
+-        If command is a string or bytes, it will be used as-is.  If it
+-        is an iterable of strings, it will be properly escaped and
+-        joined into an well-formed assuan command.
+-
+-        Keyword arguments:
+-        data_cb		-- a callback receiving data lines
+-        inquire_cb	-- a callback providing more information
+-        status_cb	-- a callback receiving status lines
+-
+-        Returns:
+-        result		-- the result of command as GPGMEError
+-
+-        Raises:
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-
+-        if util.is_a_string(command) or isinstance(command, bytes):
+-            cmd = command
+-        else:
+-            cmd = " ".join(util.percent_escape(f) for f in command)
+-
+-        errptr = gpgme.new_gpgme_error_t_p()
+-
+-        err = gpgme.gpgme_op_assuan_transact_ext(
+-            self.wrapped,
+-            cmd,
+-            (weakref.ref(self), data_cb) if data_cb else None,
+-            (weakref.ref(self), inquire_cb) if inquire_cb else None,
+-            (weakref.ref(self), status_cb) if status_cb else None,
+-            errptr)
+-
+-        if self._callback_excinfo:
+-            gpgme.gpg_raise_callback_exception(self)
+-
+-        errorcheck(err)
+-
+-        status = gpgme.gpgme_error_t_p_value(errptr)
+-        gpgme.delete_gpgme_error_t_p(errptr)
+-
+-        return GPGMEError(status) if status != 0 else None
+-
+-    def interact(self, key, func, sink=None, flags=0, fnc_value=None):
+-        """Interact with the engine
+-
+-        This method can be used to edit keys and cards interactively.
+-        KEY is the key to edit, FUNC is called repeatedly with two
+-        unicode arguments, 'keyword' and 'args'.  See the GPGME manual
+-        for details.
+-
+-        Keyword arguments:
+-        sink		-- if given, additional output is written here
+-        flags		-- use constants.INTERACT_CARD to edit a card
+-
+-        Raises:
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        if key == None:
+-            raise ValueError("First argument cannot be None")
+-
+-        if sink == None:
+-            sink = Data()
+-
+-        if fnc_value:
+-            opaquedata = (weakref.ref(self), func, fnc_value)
+-        else:
+-            opaquedata = (weakref.ref(self), func)
+-
+-        result = gpgme.gpgme_op_interact(self.wrapped, key, flags,
+-                                         opaquedata, sink)
+-        if self._callback_excinfo:
+-            gpgme.gpg_raise_callback_exception(self)
+-        errorcheck(result)
+-
+-    @property
+-    def signers(self):
+-        """Keys used for signing"""
+-        return [self.signers_enum(i) for i in range(self.signers_count())]
+-    @signers.setter
+-    def signers(self, signers):
+-        old = self.signers
+-        self.signers_clear()
+-        try:
+-            for key in signers:
+-                self.signers_add(key)
+-        except:
+-            self.signers = old
+-            raise
+-
+-    @property
+-    def pinentry_mode(self):
+-        """Pinentry mode"""
+-        return self.get_pinentry_mode()
+-    @pinentry_mode.setter
+-    def pinentry_mode(self, value):
+-        self.set_pinentry_mode(value)
+-
+-    @property
+-    def protocol(self):
+-        """Protocol to use"""
+-        return self.get_protocol()
+-    @protocol.setter
+-    def protocol(self, value):
+-        errorcheck(gpgme.gpgme_engine_check_version(value))
+-        self.set_protocol(value)
+-
+-    @property
+-    def home_dir(self):
+-        """Engine's home directory"""
+-        return self.engine_info.home_dir
+-    @home_dir.setter
+-    def home_dir(self, value):
+-        self.set_engine_info(self.protocol, home_dir=value)
+-
+-    _ctype = 'gpgme_ctx_t'
+-    _cprefix = 'gpgme_'
+-
+-    def _errorcheck(self, name):
+-        """This function should list all functions returning gpgme_error_t"""
+-        # The list of functions is created using:
+-        #
+-        # $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
+-        #   | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } "
+-        return ((name.startswith('gpgme_op_')
+-                 and not name.endswith('_result'))
+-                or name in {
+-                    'gpgme_new',
+-                    'gpgme_set_ctx_flag',
+-                    'gpgme_set_protocol',
+-                    'gpgme_set_sub_protocol',
+-                    'gpgme_set_keylist_mode',
+-                    'gpgme_set_pinentry_mode',
+-                    'gpgme_set_locale',
+-                    'gpgme_ctx_set_engine_info',
+-                    'gpgme_signers_add',
+-                    'gpgme_sig_notation_add',
+-                    'gpgme_set_sender',
+-                    'gpgme_cancel',
+-                    'gpgme_cancel_async',
+-                    'gpgme_get_key',
+-                })
+-
+-    _boolean_properties = {'armor', 'textmode', 'offline'}
+-
+-    def __del__(self):
+-        if not gpgme:
+-            # At interpreter shutdown, gpgme is set to NONE.
+-            return
+-
+-        self._free_passcb()
+-        self._free_progresscb()
+-        self._free_statuscb()
+-        if self.own and self.wrapped and gpgme.gpgme_release:
+-            gpgme.gpgme_release(self.wrapped)
+-            self.wrapped = None
+-
+-    # Implement the context manager protocol.
+-    def __enter__(self):
+-        return self
+-    def __exit__(self, type, value, tb):
+-        self.__del__()
+-
+-    def op_keylist_all(self, *args, **kwargs):
+-        self.op_keylist_start(*args, **kwargs)
+-        key = self.op_keylist_next()
+-        while key:
+-            yield key
+-            key = self.op_keylist_next()
+-        self.op_keylist_end()
+-
+-    def op_keylist_next(self):
+-        """Returns the next key in the list created
+-        by a call to op_keylist_start().  The object returned
+-        is of type Key."""
+-        ptr = gpgme.new_gpgme_key_t_p()
+-        try:
+-            errorcheck(gpgme.gpgme_op_keylist_next(self.wrapped, ptr))
+-            key = gpgme.gpgme_key_t_p_value(ptr)
+-        except errors.GPGMEError as excp:
+-            key = None
+-            if excp.getcode() != errors.EOF:
+-                raise excp
+-        gpgme.delete_gpgme_key_t_p(ptr)
+-        if key:
+-            key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
+-            return key
+-
+-    def get_key(self, fpr, secret=False):
+-        """Get a key given a fingerprint
+-
+-        Keyword arguments:
+-        secret		-- to request a secret key
+-
+-        Returns:
+-                        -- the matching key
+-
+-        Raises:
+-        KeyError	-- if the key was not found
+-        GPGMEError	-- as signaled by the underlying library
+-
+-        """
+-        ptr = gpgme.new_gpgme_key_t_p()
+-
+-        try:
+-            errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
+-        except errors.GPGMEError as e:
+-            if e.getcode() == errors.EOF:
+-                raise errors.KeyNotFound(fpr)
+-            raise e
+-
+-        key = gpgme.gpgme_key_t_p_value(ptr)
+-        gpgme.delete_gpgme_key_t_p(ptr)
+-        assert key
+-        key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
+-        return key
+-
+-    def op_trustlist_all(self, *args, **kwargs):
+-        self.op_trustlist_start(*args, **kwargs)
+-        trust = self.op_trustlist_next()
+-        while trust:
+-            yield trust
+-            trust = self.op_trustlist_next()
+-        self.op_trustlist_end()
+-
+-    def op_trustlist_next(self):
+-        """Returns the next trust item in the list created
+-        by a call to op_trustlist_start().  The object returned
+-        is of type TrustItem."""
+-        ptr = gpgme.new_gpgme_trust_item_t_p()
+-        try:
+-            errorcheck(gpgme.gpgme_op_trustlist_next(self.wrapped, ptr))
+-            trust = gpgme.gpgme_trust_item_t_p_value(ptr)
+-        except errors.GPGMEError as excp:
+-            trust = None
+-            if excp.getcode() != errors.EOF:
+-                raise
+-        gpgme.delete_gpgme_trust_item_t_p(ptr)
+-        return trust
+-
+-    def set_passphrase_cb(self, func, hook=None):
+-        """Sets the passphrase callback to the function specified by func.
+-
+-        When the system needs a passphrase, it will call func with three args:
+-        hint, a string describing the key it needs the passphrase for;
+-        desc, a string describing the passphrase it needs;
+-        prev_bad, a boolean equal True if this is a call made after
+-        unsuccessful previous attempt.
+-
+-        If hook has a value other than None it will be passed into the func
+-        as a forth argument.
+-
+-        Please see the GPGME manual for more information.
+-        """
+-        if func == None:
+-            hookdata = None
+-        else:
+-            if hook == None:
+-                hookdata = (weakref.ref(self), func)
+-            else:
+-                hookdata = (weakref.ref(self), func, hook)
+-        gpgme.gpg_set_passphrase_cb(self, hookdata)
+-
+-    def _free_passcb(self):
+-        if gpgme.gpg_set_passphrase_cb:
+-            self.set_passphrase_cb(None)
+-
+-    def set_progress_cb(self, func, hook=None):
+-        """Sets the progress meter callback to the function specified by FUNC.
+-        If FUNC is None, the callback will be cleared.
+-
+-        This function will be called to provide an interactive update
+-        of the system's progress.  The function will be called with
+-        three arguments, type, total, and current.  If HOOK is not
+-        None, it will be supplied as fourth argument.
+-
+-        Please see the GPGME manual for more information.
+-
+-        """
+-        if func == None:
+-            hookdata = None
+-        else:
+-            if hook == None:
+-                hookdata = (weakref.ref(self), func)
+-            else:
+-                hookdata = (weakref.ref(self), func, hook)
+-        gpgme.gpg_set_progress_cb(self, hookdata)
+-
+-    def _free_progresscb(self):
+-        if gpgme.gpg_set_progress_cb:
+-            self.set_progress_cb(None)
+-
+-    def set_status_cb(self, func, hook=None):
+-        """Sets the status callback to the function specified by FUNC.  If
+-        FUNC is None, the callback will be cleared.
+-
+-        The function will be called with two arguments, keyword and
+-        args.  If HOOK is not None, it will be supplied as third
+-        argument.
+-
+-        Please see the GPGME manual for more information.
+-
+-        """
+-        if func == None:
+-            hookdata = None
+-        else:
+-            if hook == None:
+-                hookdata = (weakref.ref(self), func)
+-            else:
+-                hookdata = (weakref.ref(self), func, hook)
+-        gpgme.gpg_set_status_cb(self, hookdata)
+-
+-    def _free_statuscb(self):
+-        if gpgme.gpg_set_status_cb:
+-            self.set_status_cb(None)
+-
+-    @property
+-    def engine_info(self):
+-        """Configuration of the engine currently in use"""
+-        p = self.protocol
+-        infos = [i for i in self.get_engine_info() if i.protocol == p]
+-        assert len(infos) == 1
+-        return infos[0]
+-
+-    def get_engine_info(self):
+-        """Get engine configuration
+-
+-        Returns information about all configured and installed
+-        engines.
+-
+-        Returns:
+-        infos		-- a list of engine infos
+-
+-        """
+-        return gpgme.gpgme_ctx_get_engine_info(self.wrapped)
+-
+-    def set_engine_info(self, proto, file_name=None, home_dir=None):
+-        """Change engine configuration
+-
+-        Changes the configuration of the crypto engine implementing
+-        the protocol 'proto' for the context.
+-
+-        Keyword arguments:
+-        file_name	-- engine program file name (unchanged if None)
+-        home_dir	-- configuration directory (unchanged if None)
+-
+-        """
+-        self.ctx_set_engine_info(proto, file_name, home_dir)
+-
+-    def wait(self, hang):
+-        """Wait for asynchronous call to finish. Wait forever if hang is True.
+-        Raises an exception on errors.
+-
+-        Please read the GPGME manual for more information.
+-
+-        """
+-        ptr = gpgme.new_gpgme_error_t_p()
+-        gpgme.gpgme_wait(self.wrapped, ptr, hang)
+-        status = gpgme.gpgme_error_t_p_value(ptr)
+-        gpgme.delete_gpgme_error_t_p(ptr)
+-        errorcheck(status)
+-
+-    def op_edit(self, key, func, fnc_value, out):
+-        """Start key editing using supplied callback function
+-
+-        Note: This interface is deprecated and will be removed with
+-        GPGME 1.8.  Please use .interact instead.  Furthermore, we
+-        implement this using gpgme_op_interact, so callbacks will get
+-        called with string keywords instead of numeric status
+-        messages.  Code that is using constants.STATUS_X or
+-        constants.status.X will continue to work, whereas code using
+-        magic numbers will break as a result.
+-
+-        """
+-        warnings.warn("Call to deprecated method op_edit.",
+-                      category=DeprecationWarning)
+-        return self.interact(key, func, sink=out, fnc_value=fnc_value)
+-
+-
+-class Data(GpgmeWrapper):
+-    """Data buffer
+-
+-    A lot of data has to be exchanged between the user and the crypto
+-    engine, like plaintext messages, ciphertext, signatures and
+-    information about the keys.  The technical details about
+-    exchanging the data information are completely abstracted by
+-    GPGME.  The user provides and receives the data via `gpgme_data_t'
+-    objects, regardless of the communication protocol between GPGME
+-    and the crypto engine in use.
+-
+-    This Data class is the implementation of the GpgmeData objects.
+-
+-    Please see the information about __init__ for instantiation.
+-
+-    """
+-
+-    _ctype = 'gpgme_data_t'
+-    _cprefix = 'gpgme_data_'
+-
+-    def _errorcheck(self, name):
+-        """This function should list all functions returning gpgme_error_t"""
+-        # This list is compiled using
+-        #
+-        # $ grep -v '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
+-        #   | awk "/\(gpgme_data_t/ { printf (\"'%s',\\n\", \$2) } " | sed "s/'\\*/'/"
+-        return name not in {
+-            'gpgme_data_read',
+-            'gpgme_data_write',
+-            'gpgme_data_seek',
+-            'gpgme_data_release',
+-            'gpgme_data_release_and_get_mem',
+-            'gpgme_data_get_encoding',
+-            'gpgme_data_get_file_name',
+-            'gpgme_data_identify',
+-        }
+-
+-    def __init__(self, string=None, file=None, offset=None,
+-                 length=None, cbs=None, copy=True):
+-        """Initialize a new gpgme_data_t object.
+-
+-        If no args are specified, make it an empty object.
+-
+-        If string alone is specified, initialize it with the data
+-        contained there.
+-
+-        If file, offset, and length are all specified, file must
+-        be either a filename or a file-like object, and the object
+-        will be initialized by reading the specified chunk from the file.
+-
+-        If cbs is specified, it MUST be a tuple of the form:
+-
+-        (read_cb, write_cb, seek_cb, release_cb[, hook])
+-
+-        where the first four items are functions implementing reading,
+-        writing, seeking the data, and releasing any resources once
+-        the data object is deallocated.  The functions must match the
+-        following prototypes:
+-
+-            def read(amount, hook=None):
+-                return <a b"bytes" object>
+-
+-            def write(data, hook=None):
+-                return <the number of bytes written>
+-
+-            def seek(offset, whence, hook=None):
+-                return <the new file position>
+-
+-            def release(hook=None):
+-                <return value and exceptions are ignored>
+-
+-        The functions may be bound methods.  In that case, you can
+-        simply use the 'self' reference instead of using a hook.
+-
+-        If file is specified without any other arguments, then
+-        it must be a filename, and the object will be initialized from
+-        that file.
+-
+-        """
+-        super(Data, self).__init__(None)
+-        self.data_cbs = None
+-
+-        if cbs != None:
+-            self.new_from_cbs(*cbs)
+-        elif string != None:
+-            self.new_from_mem(string, copy)
+-        elif file != None and offset != None and length != None:
+-            self.new_from_filepart(file, offset, length)
+-        elif file != None:
+-            if util.is_a_string(file):
+-                self.new_from_file(file, copy)
+-            else:
+-                self.new_from_fd(file)
+-        else:
+-            self.new()
+-
+-    def __del__(self):
+-        if not gpgme:
+-            # At interpreter shutdown, gpgme is set to NONE.
+-            return
+-
+-        if self.wrapped != None and gpgme.gpgme_data_release:
+-            gpgme.gpgme_data_release(self.wrapped)
+-            if self._callback_excinfo:
+-                gpgme.gpg_raise_callback_exception(self)
+-            self.wrapped = None
+-        self._free_datacbs()
+-
+-    # Implement the context manager protocol.
+-    def __enter__(self):
+-        return self
+-    def __exit__(self, type, value, tb):
+-        self.__del__()
+-
+-    def _free_datacbs(self):
+-        self._data_cbs = None
+-
+-    def new(self):
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        errorcheck(gpgme.gpgme_data_new(tmp))
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_mem(self, string, copy=True):
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        errorcheck(gpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy))
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_file(self, filename, copy=True):
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        try:
+-            errorcheck(gpgme.gpgme_data_new_from_file(tmp, filename, copy))
+-        except errors.GPGMEError as e:
+-            if e.getcode() == errors.INV_VALUE and not copy:
+-                raise ValueError("delayed reads are not yet supported")
+-            else:
+-                raise e
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        if hook != None:
+-            hookdata = (weakref.ref(self),
+-                        read_cb, write_cb, seek_cb, release_cb, hook)
+-        else:
+-            hookdata = (weakref.ref(self),
+-                        read_cb, write_cb, seek_cb, release_cb)
+-        gpgme.gpg_data_new_from_cbs(self, hookdata, tmp)
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_filepart(self, file, offset, length):
+-        """This wraps the GPGME gpgme_data_new_from_filepart() function.
+-        The argument "file" may be:
+-
+-        * a string specifying a file name, or
+-        * a file-like object supporting the fileno() and the mode attribute.
+-
+-        """
+-
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        filename = None
+-        fp = None
+-
+-        if util.is_a_string(file):
+-            filename = file
+-        else:
+-            fp = gpgme.fdopen(file.fileno(), file.mode)
+-            if fp == None:
+-                raise ValueError("Failed to open file from %s arg %s" % \
+-                      (str(type(file)), str(file)))
+-
+-        errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp,
+-                                                      offset, length))
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_fd(self, file):
+-        """This wraps the GPGME gpgme_data_new_from_fd() function.  The
+-        argument "file" must be a file-like object, supporting the
+-        fileno() method.
+-
+-        """
+-        tmp = gpgme.new_gpgme_data_t_p()
+-        errorcheck(gpgme.gpgme_data_new_from_fd(tmp, file.fileno()))
+-        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
+-        gpgme.delete_gpgme_data_t_p(tmp)
+-
+-    def new_from_stream(self, file):
+-        """This wrap around gpgme_data_new_from_stream is an alias for
+-        new_from_fd() method since in python there's not difference
+-        between file stream and file descriptor"""
+-        self.new_from_fd(file)
+-
+-    def write(self, buffer):
+-        """Write buffer given as string or bytes.
+-
+-        If a string is given, it is implicitly encoded using UTF-8."""
+-        written = gpgme.gpgme_data_write(self.wrapped, buffer)
+-        if written < 0:
+-            if self._callback_excinfo:
+-                gpgme.gpg_raise_callback_exception(self)
+-            else:
+-                raise GPGMEError.fromSyserror()
+-        return written
+-
+-    def read(self, size = -1):
+-        """Read at most size bytes, returned as bytes.
+-
+-        If the size argument is negative or omitted, read until EOF is reached.
+-
+-        Returns the data read, or the empty string if there was no data
+-        to read before EOF was reached."""
+-
+-        if size == 0:
+-            return ''
+-
+-        if size > 0:
+-            try:
+-                result = gpgme.gpgme_data_read(self.wrapped, size)
+-            except:
+-                if self._callback_excinfo:
+-                    gpgme.gpg_raise_callback_exception(self)
+-                else:
+-                    raise
+-            return result
+-        else:
+-            chunks = []
+-            while True:
+-                try:
+-                    result = gpgme.gpgme_data_read(self.wrapped, 4096)
+-                except:
+-                    if self._callback_excinfo:
+-                        gpgme.gpg_raise_callback_exception(self)
+-                    else:
+-                        raise
+-                if len(result) == 0:
+-                    break
+-                chunks.append(result)
+-            return b''.join(chunks)
+-
+-def pubkey_algo_string(subkey):
+-    """Return short algorithm string
+-
+-    Return a public key algorithm string (e.g. "rsa2048") for a given
+-    SUBKEY.
+-
+-    Returns:
+-    algo      - a string
+-
+-    """
+-    return gpgme.gpgme_pubkey_algo_string(subkey)
+-
+-def pubkey_algo_name(algo):
+-    """Return name of public key algorithm
+-
+-    Return the name of the public key algorithm for a given numeric
+-    algorithm id ALGO (cf. RFC4880).
+-
+-    Returns:
+-    algo      - a string
+-
+-    """
+-    return gpgme.gpgme_pubkey_algo_name(algo)
+-
+-def hash_algo_name(algo):
+-    """Return name of hash algorithm
+-
+-    Return the name of the hash algorithm for a given numeric
+-    algorithm id ALGO (cf. RFC4880).
+-
+-    Returns:
+-    algo      - a string
+-
+-    """
+-    return gpgme.gpgme_hash_algo_name(algo)
+-
+-def get_protocol_name(proto):
+-    """Get protocol description
+-
+-    Get the string describing protocol PROTO.
+-
+-    Returns:
+-    proto     - a string
+-
+-    """
+-    return gpgme.gpgme_get_protocol_name(proto)
+-
+-def addrspec_from_uid(uid):
+-    """Return the address spec
+-
+-    Return the addr-spec (cf. RFC2822 section 4.3) from a user id UID.
+-
+-    Returns:
+-    addr_spec - a string
+-
+-    """
+-    return gpgme.gpgme_addrspec_from_uid(uid)
+-
+-def check_version(version=None):
+-    return gpgme.gpgme_check_version(version)
+-
+-# check_version also makes sure that several subsystems are properly
+-# initialized, and it must be run at least once before invoking any
+-# other function.  We do it here so that the user does not have to do
+-# it unless she really wants to check for a certain version.
+-check_version()
+-
+-def engine_check_version (proto):
+-    try:
+-        errorcheck(gpgme.gpgme_engine_check_version(proto))
+-        return True
+-    except errors.GPGMEError:
+-        return False
+-
+-def get_engine_info():
+-    ptr = gpgme.new_gpgme_engine_info_t_p()
+-    try:
+-        errorcheck(gpgme.gpgme_get_engine_info(ptr))
+-        info = gpgme.gpgme_engine_info_t_p_value(ptr)
+-    except errors.GPGMEError:
+-        info = None
+-    gpgme.delete_gpgme_engine_info_t_p(ptr)
+-    return info
+-
+-def set_engine_info(proto, file_name, home_dir=None):
+-    """Changes the default configuration of the crypto engine implementing
+-    the protocol 'proto'. 'file_name' is the file name of
+-    the executable program implementing this protocol. 'home_dir' is the
+-    directory name of the configuration directory (engine's default is
+-    used if omitted)."""
+-    errorcheck(gpgme.gpgme_set_engine_info(proto, file_name, home_dir))
+-
+-def set_locale(category, value):
+-    """Sets the default locale used by contexts"""
+-    errorcheck(gpgme.gpgme_set_locale(None, category, value))
+-
+-def wait(hang):
+-    """Wait for asynchronous call on any Context  to finish.
+-    Wait forever if hang is True.
+-
+-    For finished anynch calls it returns a tuple (status, context):
+-        status  - status return by asnynchronous call.
+-        context - context which caused this call to return.
+-
+-    Please read the GPGME manual of more information."""
+-    ptr = gpgme.new_gpgme_error_t_p()
+-    context = gpgme.gpgme_wait(None, ptr, hang)
+-    status = gpgme.gpgme_error_t_p_value(ptr)
+-    gpgme.delete_gpgme_error_t_p(ptr)
+-    if context == None:
+-        errorcheck(status)
+-    else:
+-        context = Context(context)
+-    return (status, context)
+diff --git a/lang/python/gpg/errors.py b/lang/python/gpg/errors.py
+deleted file mode 100644
+index 1ce139e..0000000
+--- a/lang/python/gpg/errors.py
++++ /dev/null
+@@ -1,128 +0,0 @@
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-from . import gpgme
+-from . import util
+-
+-# To appease static analysis tools, we define some constants here.
+-# They are overwritten with the proper values by process_constants.
+-NO_ERROR = None
+-EOF = None
+-
+-util.process_constants('GPG_ERR_', globals())
+-del util
+-
+-class GpgError(Exception):
+-    pass
+-
+-class GPGMEError(GpgError):
+-    def __init__(self, error = None, message = None):
+-        self.error = error
+-        self.message = message
+-
+-    @classmethod
+-    def fromSyserror(cls):
+-        return cls(gpgme.gpgme_err_code_from_syserror())
+-
+-    def getstring(self):
+-        message = "%s: %s" % (gpgme.gpgme_strsource(self.error),
+-                              gpgme.gpgme_strerror(self.error))
+-        if self.message != None:
+-            message = "%s: %s" % (self.message, message)
+-        return message
+-
+-    def getcode(self):
+-        return gpgme.gpgme_err_code(self.error)
+-
+-    def getsource(self):
+-        return gpgme.gpgme_err_source(self.error)
+-
+-    def __str__(self):
+-        return self.getstring()
+-
+-def errorcheck(retval, extradata = None):
+-    if retval:
+-        raise GPGMEError(retval, extradata)
+-
+-class KeyNotFound(GPGMEError, KeyError):
+-    """Raised if a key was not found
+-
+-    GPGME indicates this condition with EOF, which is not very
+-    idiomatic.  We raise this error that is both a GPGMEError
+-    indicating EOF, and a KeyError.
+-
+-    """
+-    def __init__(self, keystr):
+-        self.keystr = keystr
+-        GPGMEError.__init__(self, EOF)
+-    def __str__(self):
+-        return self.keystr
+-
+-# These errors are raised in the idiomatic interface code.
+-
+-class EncryptionError(GpgError):
+-    pass
+-
+-class InvalidRecipients(EncryptionError):
+-    def __init__(self, recipients):
+-        self.recipients = recipients
+-    def __str__(self):
+-        return ", ".join("{}: {}".format(r.fpr,
+-                                         gpgme.gpgme_strerror(r.reason))
+-                         for r in self.recipients)
+-
+-class DeryptionError(GpgError):
+-    pass
+-
+-class UnsupportedAlgorithm(DeryptionError):
+-    def __init__(self, algorithm):
+-        self.algorithm = algorithm
+-    def __str__(self):
+-        return self.algorithm
+-
+-class SigningError(GpgError):
+-    pass
+-
+-class InvalidSigners(SigningError):
+-    def __init__(self, signers):
+-        self.signers = signers
+-    def __str__(self):
+-        return ", ".join("{}: {}".format(s.fpr,
+-                                         gpgme.gpgme_strerror(s.reason))
+-                         for s in self.signers)
+-
+-class VerificationError(GpgError):
+-    pass
+-
+-class BadSignatures(VerificationError):
+-    def __init__(self, result):
+-        self.result = result
+-    def __str__(self):
+-        return ", ".join("{}: {}".format(s.fpr,
+-                                         gpgme.gpgme_strerror(s.status))
+-                         for s in self.result.signatures
+-                         if s.status != NO_ERROR)
+-
+-class MissingSignatures(VerificationError):
+-    def __init__(self, result, missing):
+-        self.result = result
+-        self.missing = missing
+-    def __str__(self):
+-        return ", ".join(k.subkeys[0].fpr for k in self.missing)
+diff --git a/lang/python/gpg/results.py b/lang/python/gpg/results.py
+deleted file mode 100644
+index 46ebeec..0000000
+--- a/lang/python/gpg/results.py
++++ /dev/null
+@@ -1,118 +0,0 @@
+-# Robust result objects
+-#
+-# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-"""Robust result objects
+-
+-Results returned by the underlying library are fragile, i.e. they are
+-only valid until the next operation is performed in the context.
+-
+-We cannot arbitrarily constrain the lifetime of Python objects, we
+-therefore create deep copies of the results.
+-
+-"""
+-
+-class Result(object):
+-    """Result object
+-
+-    Describes the result of an operation.
+-
+-    """
+-
+-    """Convert to types"""
+-    _type = {}
+-
+-    """Map functions over list attributes"""
+-    _map = {}
+-
+-    """Automatically copy unless blacklisted"""
+-    _blacklist = {
+-        'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown',
+-    }
+-    def __init__(self, fragile):
+-        for key, func in self._type.items():
+-            if hasattr(fragile, key):
+-                setattr(self, key, func(getattr(fragile, key)))
+-
+-        for key, func in self._map.items():
+-            if hasattr(fragile, key):
+-                setattr(self, key, list(map(func, getattr(fragile, key))))
+-
+-        for key in dir(fragile):
+-            if key.startswith('_') or key in self._blacklist:
+-                continue
+-            if hasattr(self, key):
+-                continue
+-
+-            setattr(self, key, getattr(fragile, key))
+-
+-    def __repr__(self):
+-        return '{}({})'.format(
+-            self.__class__.__name__,
+-            ', '.join('{}={!r}'.format(k, getattr(self, k))
+-                      for k in dir(self) if not k.startswith('_')))
+-
+-class InvalidKey(Result):
+-    pass
+-
+-class EncryptResult(Result):
+-    _map = dict(invalid_recipients=InvalidKey)
+-
+-class Recipient(Result):
+-    pass
+-
+-class DecryptResult(Result):
+-    _type = dict(wrong_key_usage=bool)
+-    _map = dict(recipients=Recipient)
+-
+-class NewSignature(Result):
+-    pass
+-
+-class SignResult(Result):
+-    _map = dict(invalid_signers=InvalidKey, signatures=NewSignature)
+-
+-class Notation(Result):
+-    pass
+-
+-class Signature(Result):
+-    _type = dict(wrong_key_usage=bool, chain_model=bool)
+-    _map = dict(notations=Notation)
+-
+-class VerifyResult(Result):
+-    _map = dict(signatures=Signature)
+-
+-class ImportStatus(Result):
+-    pass
+-
+-class ImportResult(Result):
+-    _map = dict(imports=ImportStatus)
+-
+-class GenkeyResult(Result):
+-    _type = dict(primary=bool, sub=bool)
+-
+-class KeylistResult(Result):
+-    _type = dict(truncated=bool)
+-
+-class VFSMountResult(Result):
+-    pass
+-
+-class EngineInfo(Result):
+-    pass
+diff --git a/lang/python/gpg/util.py b/lang/python/gpg/util.py
+deleted file mode 100644
+index e4fca4c..0000000
+--- a/lang/python/gpg/util.py
++++ /dev/null
+@@ -1,53 +0,0 @@
+-# Copyright (C) 2016 g10 Code GmbH
+-# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
+-# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-#
+-#    This library 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.
+-#
+-#    This library 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 library; if not, write to the Free Software
+-#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function, unicode_literals
+-del absolute_import, print_function, unicode_literals
+-
+-import sys
+-
+-def process_constants(prefix, scope):
+-    """Called by the constant modules to load up the constants from the C
+-    library starting with PREFIX.  Matching constants will be inserted
+-    into SCOPE with PREFIX stripped from the names.  Returns the names
+-    of inserted constants.
+-
+-    """
+-    from . import gpgme
+-    index = len(prefix)
+-    constants = {identifier[index:]: getattr(gpgme, identifier)
+-                 for identifier in dir(gpgme)
+-                 if identifier.startswith(prefix)}
+-    scope.update(constants)
+-    return list(constants.keys())
+-
+-def percent_escape(s):
+-    return ''.join(
+-        '%{0:2x}'.format(ord(c))
+-        if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c
+-        for c in s)
+-
+-# Python2/3 compatibility
+-if sys.version_info[0] == 3:
+-    # Python3
+-    def is_a_string(x):
+-        return isinstance(x, str)
+-else:
+-    # Python2
+-    def is_a_string(x):
+-        return isinstance(x, basestring)
+diff --git a/lang/python/gpg/version.py.in b/lang/python/gpg/version.py.in
+deleted file mode 100644
+index 1a1baf0..0000000
+--- a/lang/python/gpg/version.py.in
++++ /dev/null
+@@ -1,68 +0,0 @@
+-# Copyright (C) 2016 g10 Code GmbH
+-# Copyright (C) 2015 Ben McGinnes <ben at adversary.org>
+-# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
+-#
+-# This library 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.
+-#
+-# This library 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 library; if not, write to the Free Software
+-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+-
+-from __future__ import absolute_import, print_function
+-del absolute_import, print_function
+-
+-from . import gpgme
+-
+-productname = 'gpg'
+-versionstr = "@VERSION@"
+-gpgme_versionstr = gpgme.GPGME_VERSION
+-in_tree_build = bool(gpgme.cvar.gpg_in_tree_build)
+-
+-versionlist = versionstr.split(".")
+-major = versionlist[0]
+-minor = versionlist[1]
+-patch = versionlist[2]
+-
+-copyright = """\
+-Copyright (C) 2016 g10 Code GmbH
+-Copyright (C) 2015 Ben McGinnes
+-Copyright (C) 2014-2015 Martin Albrecht
+-Copyright (C) 2004-2008 Igor Belyi
+-Copyright (C) 2002 John Goerzen"""
+-
+-author = "The GnuPG hackers"
+-author_email = "gnupg-devel at gnupg.org"
+-
+-description = "Python support for GPGME GnuPG cryptography library"
+-homepage = "https://gnupg.org"
+-
+-license = """Copyright (C) 2016 g10 Code GmbH
+-Copyright (C) 2015 Ben McGinnes <ben at adversary.org>
+-Copyright (C) 2014, 2015 Martin Albrecht <martinralbrecht at googlemail.com>
+-Copyright (C) 2004, 2008 Igor Belyi <belyi at users.sourceforge.net>
+-Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
+-
+-This library 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.
+-
+-This library 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 library; if not, write to the Free Software
+-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA"""
+-
+-# Interface hygiene.  Keep this at the end.
+-del gpgme
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index 2114aaf..5d94c70 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -38,18 +38,17 @@ gpgme_config = ["gpgme-config"] + gpgme_config_flags
+ gpgme_h = ""
+ include_dirs = [os.getcwd()]
+ library_dirs = []
+-vpath_build = os.environ.get('srcdir', '.') != '.'
+ in_tree = False
+ extra_swig_opts = []
+ extra_macros = dict()
+ 
+-abs_top_builddir = os.environ.get("abs_top_builddir")
+-if abs_top_builddir:
++top_builddir = os.environ.get("top_builddir")
++if top_builddir:
+     # In-tree build.
+     in_tree = True
+-    gpgme_config = [os.path.join(abs_top_builddir, "src/gpgme-config")] + gpgme_config_flags
+-    gpgme_h = os.path.join(abs_top_builddir, "src/gpgme.h")
+-    library_dirs = [os.path.join(abs_top_builddir, "src/.libs")] # XXX uses libtool internals
++    gpgme_config = [os.path.join(top_builddir, "src/gpgme-config")] + gpgme_config_flags
++    gpgme_h = os.path.join(top_builddir, "src/gpgme.h")
++    library_dirs = [os.path.join(top_builddir, "src/.libs")] # XXX uses libtool internals
+     extra_macros.update(
+         HAVE_CONFIG_H=1,
+         HAVE_DATA_H=1,
+@@ -210,23 +209,21 @@ class BuildExtFirstHack(build):
+         # Copy due to http://bugs.python.org/issue2624
+         # Avoid creating in srcdir
+         for source, target in ((in_srcdir(n), in_build_base(n))
+-                               for n in ('gpgme.i', 'helpers.c')):
++                               for n in ('gpgme.i', 'helpers.c', 'private.h', 'helpers.h')):
+             if not up_to_date(source, target):
+                 shutil.copy2(source, target)
+ 
+-    def run(self):
+-        self._generate()
+-
+         # Append generated files via build_base
+         if not os.path.exists(os.path.join(self.build_lib, "gpg")):
+             os.makedirs(os.path.join(self.build_lib, "gpg"))
++        shutil.copy2("version.py", os.path.join(self.build_lib, "gpg"))
++
++    def run(self):
++        self._generate()
+ 
+         swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
+         swig_opts.extend(['-I' + self.build_base,
+-                          '-I' + in_srcdir('.'),
+                           '-outdir', os.path.join(self.build_lib, 'gpg')])
+-        if vpath_build:
+-            include_dirs.append(in_srcdir('.'))
+         include_dirs.append(self.build_base)
+ 
+         self.run_command('build_ext')
+diff --git a/lang/python/src/__init__.py b/lang/python/src/__init__.py
+new file mode 100644
+index 0000000..385b17e
+--- /dev/null
++++ b/lang/python/src/__init__.py
+@@ -0,0 +1,121 @@
++# Copyright (C) 2016 g10 Code GmbH
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++# This library 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.
++#
++# This library 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 library; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++"""gpg: GnuPG Interface for Python (GPGME bindings)
++
++Welcome to gpg, the GnuPG Interface for Python.
++
++The latest release of this package may be obtained from
++https://www.gnupg.org
++
++FEATURES
++--------
++
++ * Feature-rich, full implementation of the GPGME library.  Supports
++   all GPGME features.  Callback functions may be written in pure
++   Python.  Exceptions raised in callbacks are properly propagated.
++
++ * Ability to sign, encrypt, decrypt, and verify data.
++
++ * Ability to list keys, export and import keys, and manage the keyring.
++
++ * Fully object-oriented with convenient classes and modules.
++
++QUICK EXAMPLE
++-------------
++
++    >>> import gpg
++    >>> with gpg.Context() as c:
++    >>> with gpg.Context() as c:
++    ...     cipher, _, _ = c.encrypt("Hello world :)".encode(),
++    ...                              passphrase="abc")
++    ...     c.decrypt(cipher, passphrase="abc")
++    ...
++    (b'Hello world :)',
++     <gpg.results.DecryptResult object at 0x7f5ab8121080>,
++     <gpg.results.VerifyResult object at 0x7f5ab81219b0>)
++
++GENERAL OVERVIEW
++----------------
++
++For those of you familiar with GPGME, you will be right at home here.
++
++The python gpg module is, for the most part, a direct interface to the C GPGME
++library.  However, it is re-packaged in a more Pythonic way --
++object-oriented with classes and modules.  Take a look at the classes
++defined here -- they correspond directly to certain object types in GPGME
++for C.  For instance, the following C code:
++
++gpgme_ctx_t context;
++gpgme_new(&context);
++...
++gpgme_op_encrypt(context, recp, 1, plain, cipher);
++
++Translates into the following Python code:
++
++context = core.Context()
++...
++context.op_encrypt(recp, 1, plain, cipher)
++
++The Python module automatically does error-checking and raises Python
++exception gpg.errors.GPGMEError when GPGME signals an error. getcode()
++and getsource() of this exception return code and source of the error.
++
++IMPORTANT NOTE
++--------------
++This documentation only covers a small subset of available GPGME functions and
++methods.  Please consult the documentation for the C library
++for comprehensive coverage.
++
++This library uses Python's reflection to automatically detect the methods
++that are available for each class, and as such, most of those methods
++do not appear explicitly anywhere. You can use dir() python built-in command
++on an object to see what methods and fields it has but their meaning can
++be found only in GPGME documentation.
++
++FOR MORE INFORMATION
++--------------------
++GnuPG homepage: https://www.gnupg.org/
++GPGME documentation: https://www.gnupg.org/documentation/manuals/gpgme/
++
++"""
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import core
++from . import errors
++from . import constants
++from . import util
++from . import callbacks
++from . import version
++from .core import Context
++from .core import Data
++
++# Interface hygiene.
++
++# Drop the low-level gpgme that creeps in for some reason.
++gpgme = None
++del gpgme
++
++# This is a white-list of symbols.  Any other will alert pyflakes.
++_ = [Context, Data, core, errors, constants, util, callbacks, version]
++del _
++
++__all__ = ["Context", "Data",
++           "core", "errors", "constants", "util", "callbacks", "version"]
+diff --git a/lang/python/src/callbacks.py b/lang/python/src/callbacks.py
+new file mode 100644
+index 0000000..b25a9a7
+--- /dev/null
++++ b/lang/python/src/callbacks.py
+@@ -0,0 +1,49 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from getpass import getpass
++
++def passphrase_stdin(hint, desc, prev_bad, hook=None):
++    """This is a sample callback that will read a passphrase from
++    the terminal.  The hook here, if present, will be used to describe
++    why the passphrase is needed."""
++    why = ''
++    if hook != None:
++        why = ' ' + hook
++    if prev_bad:
++        why += ' (again)'
++    print("Please supply %s' password%s:" % (hint, why))
++    return getpass()
++
++def progress_stdout(what, type, current, total, hook=None):
++    print("PROGRESS UPDATE: what = %s, type = %d, current = %d, total = %d" %\
++          (what, type, current, total))
++
++def readcb_fh(count, hook):
++    """A callback for data.  hook should be a Python file-like object."""
++    if count:
++        # Should return '' on EOF
++        return hook.read(count)
++    else:
++        # Wants to rewind.
++        if not hasattr(hook, 'seek'):
++            return None
++        hook.seek(0, 0)
++        return None
+diff --git a/lang/python/src/constants/__init__.py b/lang/python/src/constants/__init__.py
+new file mode 100644
+index 0000000..484ffd2
+--- /dev/null
++++ b/lang/python/src/constants/__init__.py
+@@ -0,0 +1,142 @@
++# Constants.
++#
++# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_', globals())
++del util
++
++# For convenience, we import the modules here.
++from . import data, keylist, sig, tofu # The subdirs.
++from . import create, event, keysign, md, pk, protocol, sigsum, status, validity
++
++# A complication arises because 'import' is a reserved keyword.
++# Import it as 'Import' instead.
++globals()['Import'] = getattr(__import__('', globals(), locals(),
++                                         [str('import')], 1), "import")
++
++__all__ = ['data', 'event', 'import', 'keysign', 'keylist', 'md', 'pk',
++           'protocol', 'sig', 'sigsum', 'status', 'tofu', 'validity', 'create']
++
++# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
++# implement gpg.Context.op_edit using gpgme_op_interact, so the
++# callbacks will be called with string keywords instead of numeric
++# status messages.  Code that is using these constants will continue
++# to work.
++
++STATUS_ABORT = "ABORT"
++STATUS_ALREADY_SIGNED = "ALREADY_SIGNED"
++STATUS_ATTRIBUTE = "ATTRIBUTE"
++STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
++STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE"
++STATUS_BADARMOR = "BADARMOR"
++STATUS_BADMDC = "BADMDC"
++STATUS_BADSIG = "BADSIG"
++STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
++STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
++STATUS_BEGIN_SIGNING = "BEGIN_SIGNING"
++STATUS_BEGIN_STREAM = "BEGIN_STREAM"
++STATUS_CARDCTRL = "CARDCTRL"
++STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED"
++STATUS_DECRYPTION_INFO = "DECRYPTION_INFO"
++STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY"
++STATUS_DELETE_PROBLEM = "DELETE_PROBLEM"
++STATUS_ENC_TO = "ENC_TO"
++STATUS_END_DECRYPTION = "END_DECRYPTION"
++STATUS_END_ENCRYPTION = "END_ENCRYPTION"
++STATUS_END_STREAM = "END_STREAM"
++STATUS_ENTER = "ENTER"
++STATUS_ERRMDC = "ERRMDC"
++STATUS_ERROR = "ERROR"
++STATUS_ERRSIG = "ERRSIG"
++STATUS_EXPKEYSIG = "EXPKEYSIG"
++STATUS_EXPSIG = "EXPSIG"
++STATUS_FAILURE = "FAILURE"
++STATUS_FILE_DONE = "FILE_DONE"
++STATUS_FILE_ERROR = "FILE_ERROR"
++STATUS_FILE_START = "FILE_START"
++STATUS_GET_BOOL = "GET_BOOL"
++STATUS_GET_HIDDEN = "GET_HIDDEN"
++STATUS_GET_LINE = "GET_LINE"
++STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
++STATUS_GOODMDC = "GOODMDC"
++STATUS_GOODSIG = "GOODSIG"
++STATUS_GOT_IT = "GOT_IT"
++STATUS_IMPORT_OK = "IMPORT_OK"
++STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM"
++STATUS_IMPORT_RES = "IMPORT_RES"
++STATUS_IMPORTED = "IMPORTED"
++STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
++STATUS_INV_RECP = "INV_RECP"
++STATUS_INV_SGNR = "INV_SGNR"
++STATUS_KEY_CONSIDERED = "KEY_CONSIDERED"
++STATUS_KEY_CREATED = "KEY_CREATED"
++STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED"
++STATUS_KEYEXPIRED = "KEYEXPIRED"
++STATUS_KEYREVOKED = "KEYREVOKED"
++STATUS_LEAVE = "LEAVE"
++STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
++STATUS_MOUNTPOINT = "MOUNTPOINT"
++STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE"
++STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
++STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
++STATUS_NEWSIG = "NEWSIG"
++STATUS_NO_PUBKEY = "NO_PUBKEY"
++STATUS_NO_RECP = "NO_RECP"
++STATUS_NO_SECKEY = "NO_SECKEY"
++STATUS_NO_SGNR = "NO_SGNR"
++STATUS_NODATA = "NODATA"
++STATUS_NOTATION_DATA = "NOTATION_DATA"
++STATUS_NOTATION_FLAGS = "NOTATION_FLAGS"
++STATUS_NOTATION_NAME = "NOTATION_NAME"
++STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
++STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD"
++STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
++STATUS_PLAINTEXT = "PLAINTEXT"
++STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
++STATUS_POLICY_URL = "POLICY_URL"
++STATUS_PROGRESS = "PROGRESS"
++STATUS_REVKEYSIG = "REVKEYSIG"
++STATUS_RSA_OR_IDEA = "RSA_OR_IDEA"
++STATUS_SC_OP_FAILURE = "SC_OP_FAILURE"
++STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS"
++STATUS_SESSION_KEY = "SESSION_KEY"
++STATUS_SHM_GET = "SHM_GET"
++STATUS_SHM_GET_BOOL = "SHM_GET_BOOL"
++STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
++STATUS_SHM_INFO = "SHM_INFO"
++STATUS_SIG_CREATED = "SIG_CREATED"
++STATUS_SIG_ID = "SIG_ID"
++STATUS_SIG_SUBPACKET = "SIG_SUBPACKET"
++STATUS_SIGEXPIRED = "SIGEXPIRED"
++STATUS_SUCCESS = "SUCCESS"
++STATUS_TOFU_STATS = "TOFU_STATS"
++STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG"
++STATUS_TOFU_USER = "TOFU_USER"
++STATUS_TRUNCATED = "TRUNCATED"
++STATUS_TRUST_FULLY = "TRUST_FULLY"
++STATUS_TRUST_MARGINAL = "TRUST_MARGINAL"
++STATUS_TRUST_NEVER = "TRUST_NEVER"
++STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE"
++STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED"
++STATUS_UNEXPECTED = "UNEXPECTED"
++STATUS_USERID_HINT = "USERID_HINT"
++STATUS_VALIDSIG = "VALIDSIG"
+diff --git a/lang/python/src/constants/create.py b/lang/python/src/constants/create.py
+new file mode 100644
+index 0000000..132e96d
+--- /dev/null
++++ b/lang/python/src/constants/create.py
+@@ -0,0 +1,25 @@
++# Flags for key creation
++#
++# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_CREATE_', globals())
++del util
+diff --git a/lang/python/src/constants/data/__init__.py b/lang/python/src/constants/data/__init__.py
+new file mode 100644
+index 0000000..8274ab9
+--- /dev/null
++++ b/lang/python/src/constants/data/__init__.py
+@@ -0,0 +1,6 @@
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import encoding
++__all__ = ['encoding']
+diff --git a/lang/python/src/constants/data/encoding.py b/lang/python/src/constants/data/encoding.py
+new file mode 100644
+index 0000000..e76a22e
+--- /dev/null
++++ b/lang/python/src/constants/data/encoding.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_DATA_ENCODING_', globals())
++del util
+diff --git a/lang/python/src/constants/event.py b/lang/python/src/constants/event.py
+new file mode 100644
+index 0000000..1b14d1d
+--- /dev/null
++++ b/lang/python/src/constants/event.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_EVENT_', globals())
++del util
+diff --git a/lang/python/src/constants/import.py b/lang/python/src/constants/import.py
+new file mode 100644
+index 0000000..47c296c
+--- /dev/null
++++ b/lang/python/src/constants/import.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_IMPORT_', globals())
++del util
+diff --git a/lang/python/src/constants/keylist/__init__.py b/lang/python/src/constants/keylist/__init__.py
+new file mode 100644
+index 0000000..2ce0edf
+--- /dev/null
++++ b/lang/python/src/constants/keylist/__init__.py
+@@ -0,0 +1,6 @@
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import mode
++__all__ = ['mode']
+diff --git a/lang/python/src/constants/keylist/mode.py b/lang/python/src/constants/keylist/mode.py
+new file mode 100644
+index 0000000..39e1819
+--- /dev/null
++++ b/lang/python/src/constants/keylist/mode.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_KEYLIST_MODE_', globals())
++del util
+diff --git a/lang/python/src/constants/keysign.py b/lang/python/src/constants/keysign.py
+new file mode 100644
+index 0000000..fccdbc4
+--- /dev/null
++++ b/lang/python/src/constants/keysign.py
+@@ -0,0 +1,25 @@
++# Flags for key signing
++#
++# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_KEYSIGN_', globals())
++del util
+diff --git a/lang/python/src/constants/md.py b/lang/python/src/constants/md.py
+new file mode 100644
+index 0000000..f3e8bbd
+--- /dev/null
++++ b/lang/python/src/constants/md.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_MD_', globals())
++del util
+diff --git a/lang/python/src/constants/pk.py b/lang/python/src/constants/pk.py
+new file mode 100644
+index 0000000..6bf2a21
+--- /dev/null
++++ b/lang/python/src/constants/pk.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_PK_', globals())
++del util
+diff --git a/lang/python/src/constants/protocol.py b/lang/python/src/constants/protocol.py
+new file mode 100644
+index 0000000..d086bbd
+--- /dev/null
++++ b/lang/python/src/constants/protocol.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_PROTOCOL_', globals())
++del util
+diff --git a/lang/python/src/constants/sig/__init__.py b/lang/python/src/constants/sig/__init__.py
+new file mode 100644
+index 0000000..39d4e6e
+--- /dev/null
++++ b/lang/python/src/constants/sig/__init__.py
+@@ -0,0 +1,6 @@
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import mode, notation
++__all__ = ['mode', 'notation']
+diff --git a/lang/python/src/constants/sig/mode.py b/lang/python/src/constants/sig/mode.py
+new file mode 100644
+index 0000000..0f4f0ef
+--- /dev/null
++++ b/lang/python/src/constants/sig/mode.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_SIG_MODE_', globals())
++del util
+diff --git a/lang/python/src/constants/sig/notation.py b/lang/python/src/constants/sig/notation.py
+new file mode 100644
+index 0000000..9a79e01
+--- /dev/null
++++ b/lang/python/src/constants/sig/notation.py
+@@ -0,0 +1,25 @@
++# Constants for signature notation data.
++#
++# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_SIG_NOTATION_', globals())
++del util
+diff --git a/lang/python/src/constants/sigsum.py b/lang/python/src/constants/sigsum.py
+new file mode 100644
+index 0000000..09ef9d7
+--- /dev/null
++++ b/lang/python/src/constants/sigsum.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_SIGSUM_', globals())
++del util
+diff --git a/lang/python/src/constants/status.py b/lang/python/src/constants/status.py
+new file mode 100644
+index 0000000..a0ad073
+--- /dev/null
++++ b/lang/python/src/constants/status.py
+@@ -0,0 +1,124 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
++# implement gpg.Context.op_edit using gpgme_op_interact, so the
++# callbacks will be called with string keywords instead of numeric
++# status messages.  Code that is using these constants will continue
++# to work.
++
++ABORT = "ABORT"
++ALREADY_SIGNED = "ALREADY_SIGNED"
++ATTRIBUTE = "ATTRIBUTE"
++BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
++BAD_PASSPHRASE = "BAD_PASSPHRASE"
++BADARMOR = "BADARMOR"
++BADMDC = "BADMDC"
++BADSIG = "BADSIG"
++BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
++BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
++BEGIN_SIGNING = "BEGIN_SIGNING"
++BEGIN_STREAM = "BEGIN_STREAM"
++CARDCTRL = "CARDCTRL"
++DECRYPTION_FAILED = "DECRYPTION_FAILED"
++DECRYPTION_INFO = "DECRYPTION_INFO"
++DECRYPTION_OKAY = "DECRYPTION_OKAY"
++DELETE_PROBLEM = "DELETE_PROBLEM"
++ENC_TO = "ENC_TO"
++END_DECRYPTION = "END_DECRYPTION"
++END_ENCRYPTION = "END_ENCRYPTION"
++END_STREAM = "END_STREAM"
++ENTER = "ENTER"
++ERRMDC = "ERRMDC"
++ERROR = "ERROR"
++ERRSIG = "ERRSIG"
++EXPKEYSIG = "EXPKEYSIG"
++EXPSIG = "EXPSIG"
++FAILURE = "FAILURE"
++FILE_DONE = "FILE_DONE"
++FILE_ERROR = "FILE_ERROR"
++FILE_START = "FILE_START"
++GET_BOOL = "GET_BOOL"
++GET_HIDDEN = "GET_HIDDEN"
++GET_LINE = "GET_LINE"
++GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
++GOODMDC = "GOODMDC"
++GOODSIG = "GOODSIG"
++GOT_IT = "GOT_IT"
++IMPORT_OK = "IMPORT_OK"
++IMPORT_PROBLEM = "IMPORT_PROBLEM"
++IMPORT_RES = "IMPORT_RES"
++IMPORTED = "IMPORTED"
++INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
++INV_RECP = "INV_RECP"
++INV_SGNR = "INV_SGNR"
++KEY_CONSIDERED = "KEY_CONSIDERED"
++KEY_CREATED = "KEY_CREATED"
++KEY_NOT_CREATED = "KEY_NOT_CREATED"
++KEYEXPIRED = "KEYEXPIRED"
++KEYREVOKED = "KEYREVOKED"
++LEAVE = "LEAVE"
++MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
++MOUNTPOINT = "MOUNTPOINT"
++NEED_PASSPHRASE = "NEED_PASSPHRASE"
++NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
++NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
++NEWSIG = "NEWSIG"
++NO_PUBKEY = "NO_PUBKEY"
++NO_RECP = "NO_RECP"
++NO_SECKEY = "NO_SECKEY"
++NO_SGNR = "NO_SGNR"
++NODATA = "NODATA"
++NOTATION_DATA = "NOTATION_DATA"
++NOTATION_FLAGS = "NOTATION_FLAGS"
++NOTATION_NAME = "NOTATION_NAME"
++PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
++PKA_TRUST_BAD = "PKA_TRUST_BAD"
++PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
++PLAINTEXT = "PLAINTEXT"
++PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
++POLICY_URL = "POLICY_URL"
++PROGRESS = "PROGRESS"
++REVKEYSIG = "REVKEYSIG"
++RSA_OR_IDEA = "RSA_OR_IDEA"
++SC_OP_FAILURE = "SC_OP_FAILURE"
++SC_OP_SUCCESS = "SC_OP_SUCCESS"
++SESSION_KEY = "SESSION_KEY"
++SHM_GET = "SHM_GET"
++SHM_GET_BOOL = "SHM_GET_BOOL"
++SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
++SHM_INFO = "SHM_INFO"
++SIG_CREATED = "SIG_CREATED"
++SIG_ID = "SIG_ID"
++SIG_SUBPACKET = "SIG_SUBPACKET"
++SIGEXPIRED = "SIGEXPIRED"
++SUCCESS = "SUCCESS"
++TOFU_STATS = "TOFU_STATS"
++TOFU_STATS_LONG = "TOFU_STATS_LONG"
++TOFU_USER = "TOFU_USER"
++TRUNCATED = "TRUNCATED"
++TRUST_FULLY = "TRUST_FULLY"
++TRUST_MARGINAL = "TRUST_MARGINAL"
++TRUST_NEVER = "TRUST_NEVER"
++TRUST_ULTIMATE = "TRUST_ULTIMATE"
++TRUST_UNDEFINED = "TRUST_UNDEFINED"
++UNEXPECTED = "UNEXPECTED"
++USERID_HINT = "USERID_HINT"
++VALIDSIG = "VALIDSIG"
+diff --git a/lang/python/src/constants/tofu/__init__.py b/lang/python/src/constants/tofu/__init__.py
+new file mode 100644
+index 0000000..819a58b
+--- /dev/null
++++ b/lang/python/src/constants/tofu/__init__.py
+@@ -0,0 +1,24 @@
++# TOFU
++#
++# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import policy
++__all__ = ['policy']
+diff --git a/lang/python/src/constants/tofu/policy.py b/lang/python/src/constants/tofu/policy.py
+new file mode 100644
+index 0000000..5a61f06
+--- /dev/null
++++ b/lang/python/src/constants/tofu/policy.py
+@@ -0,0 +1,25 @@
++# TOFU policies
++#
++# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_TOFU_POLICY_', globals())
++del util
+diff --git a/lang/python/src/constants/validity.py b/lang/python/src/constants/validity.py
+new file mode 100644
+index 0000000..d3c5345
+--- /dev/null
++++ b/lang/python/src/constants/validity.py
+@@ -0,0 +1,23 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from gpg import util
++util.process_constants('GPGME_VALIDITY_', globals())
++del util
+diff --git a/lang/python/src/core.py b/lang/python/src/core.py
+new file mode 100644
+index 0000000..632f4ca
+--- /dev/null
++++ b/lang/python/src/core.py
+@@ -0,0 +1,1490 @@
++# Copyright (C) 2016-2017 g10 Code GmbH
++# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++"""Core functionality
++
++Core functionality of GPGME wrapped in a object-oriented fashion.
++Provides the 'Context' class for performing cryptographic operations,
++and the 'Data' class describing buffers of data.
++
++"""
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++import re
++import os
++import warnings
++import weakref
++from . import gpgme
++from .errors import errorcheck, GPGMEError
++from . import constants
++from . import errors
++from . import util
++
++class GpgmeWrapper(object):
++    """Base wrapper class
++
++    Not to be instantiated directly.
++
++    """
++
++    def __init__(self, wrapped):
++        self._callback_excinfo = None
++        self.wrapped = wrapped
++
++    def __repr__(self):
++        return '<{}/{!r}>'.format(super(GpgmeWrapper, self).__repr__(),
++                                  self.wrapped)
++
++    def __str__(self):
++        acc = ['{}.{}'.format(__name__, self.__class__.__name__)]
++        flags = [f for f in self._boolean_properties if getattr(self, f)]
++        if flags:
++            acc.append('({})'.format(' '.join(flags)))
++
++        return '<{}>'.format(' '.join(acc))
++
++    def __hash__(self):
++        return hash(repr(self.wrapped))
++
++    def __eq__(self, other):
++        if other == None:
++            return False
++        else:
++            return repr(self.wrapped) == repr(other.wrapped)
++
++    @property
++    def _ctype(self):
++        """The name of the c type wrapped by this class
++
++        Must be set by child classes.
++
++        """
++        raise NotImplementedError()
++
++    @property
++    def _cprefix(self):
++        """The common prefix of c functions wrapped by this class
++
++        Must be set by child classes.
++
++        """
++        raise NotImplementedError()
++
++    def _errorcheck(self, name):
++        """Must be implemented by child classes.
++
++        This function must return a trueish value for all c functions
++        returning gpgme_error_t."""
++        raise NotImplementedError()
++
++    """The set of all boolean properties"""
++    _boolean_properties = set()
++
++    def __wrap_boolean_property(self, key, do_set=False, value=None):
++        get_func = getattr(gpgme,
++                           "{}get_{}".format(self._cprefix, key))
++        set_func = getattr(gpgme,
++                           "{}set_{}".format(self._cprefix, key))
++        def get(slf):
++            return bool(get_func(slf.wrapped))
++        def set_(slf, value):
++            set_func(slf.wrapped, bool(value))
++
++        p = property(get, set_, doc="{} flag".format(key))
++        setattr(self.__class__, key, p)
++
++        if do_set:
++            set_(self, bool(value))
++        else:
++            return get(self)
++
++    _munge_docstring = re.compile(r'gpgme_([^(]*)\(([^,]*), (.*\) -> .*)')
++    def __getattr__(self, key):
++        """On-the-fly generation of wrapper methods and properties"""
++        if key[0] == '_' or self._cprefix == None:
++            return None
++
++        if key in self._boolean_properties:
++            return self.__wrap_boolean_property(key)
++
++        name = self._cprefix + key
++        func = getattr(gpgme, name)
++
++        if self._errorcheck(name):
++            def _funcwrap(slf, *args):
++                result = func(slf.wrapped, *args)
++                if slf._callback_excinfo:
++                    gpgme.gpg_raise_callback_exception(slf)
++                return errorcheck(result, "Invocation of " + name)
++        else:
++            def _funcwrap(slf, *args):
++                result = func(slf.wrapped, *args)
++                if slf._callback_excinfo:
++                    gpgme.gpg_raise_callback_exception(slf)
++                return result
++
++        doc = self._munge_docstring.sub(r'\2.\1(\3', getattr(func, "__doc__"))
++        _funcwrap.__doc__ = doc
++
++        # Monkey-patch the class.
++        setattr(self.__class__, key, _funcwrap)
++
++        # Bind the method to 'self'.
++        def wrapper(*args):
++            return _funcwrap(self, *args)
++        wrapper.__doc__ = doc
++
++        return wrapper
++
++    def __setattr__(self, key, value):
++        """On-the-fly generation of properties"""
++        if key in self._boolean_properties:
++            self.__wrap_boolean_property(key, True, value)
++        else:
++            super(GpgmeWrapper, self).__setattr__(key, value)
++
++class Context(GpgmeWrapper):
++    """Context for cryptographic operations
++
++    All cryptographic operations in GPGME are performed within a
++    context, which contains the internal state of the operation as
++    well as configuration parameters.  By using several contexts you
++    can run several cryptographic operations in parallel, with
++    different configuration.
++
++    Access to a context must be synchronized.
++
++    """
++
++    def __init__(self, armor=False, textmode=False, offline=False,
++                 signers=[], pinentry_mode=constants.PINENTRY_MODE_DEFAULT,
++                 protocol=constants.PROTOCOL_OpenPGP,
++                 wrapped=None, home_dir=None):
++        """Construct a context object
++
++        Keyword arguments:
++        armor		-- enable ASCII armoring (default False)
++        textmode	-- enable canonical text mode (default False)
++        offline		-- do not contact external key sources (default False)
++        signers		-- list of keys used for signing (default [])
++        pinentry_mode	-- pinentry mode (default PINENTRY_MODE_DEFAULT)
++        protocol	-- protocol to use (default PROTOCOL_OpenPGP)
++        home_dir        -- state directory (default is the engine default)
++
++        """
++        if wrapped:
++            self.own = False
++        else:
++            tmp = gpgme.new_gpgme_ctx_t_p()
++            errorcheck(gpgme.gpgme_new(tmp))
++            wrapped = gpgme.gpgme_ctx_t_p_value(tmp)
++            gpgme.delete_gpgme_ctx_t_p(tmp)
++            self.own = True
++        super(Context, self).__init__(wrapped)
++        self.armor = armor
++        self.textmode = textmode
++        self.offline = offline
++        self.signers = signers
++        self.pinentry_mode = pinentry_mode
++        self.protocol = protocol
++        self.home_dir = home_dir
++
++    def __repr__(self):
++        return (
++            "Context(armor={0.armor}, "
++            "textmode={0.textmode}, offline={0.offline}, "
++            "signers={0.signers}, pinentry_mode={0.pinentry_mode}, "
++            "protocol={0.protocol}, home_dir={0.home_dir}"
++            ")").format(self)
++
++    def encrypt(self, plaintext, recipients=[], sign=True, sink=None,
++                passphrase=None, always_trust=False, add_encrypt_to=False,
++                prepare=False, expect_sign=False, compress=True):
++        """Encrypt data
++
++        Encrypt the given plaintext for the given recipients.  If the
++        list of recipients is empty, the data is encrypted
++        symmetrically with a passphrase.
++
++        The passphrase can be given as parameter, using a callback
++        registered at the context, or out-of-band via pinentry.
++
++        Keyword arguments:
++        recipients	-- list of keys to encrypt to
++        sign		-- sign plaintext (default True)
++        sink		-- write result to sink instead of returning it
++        passphrase	-- for symmetric encryption
++        always_trust	-- always trust the keys (default False)
++        add_encrypt_to	-- encrypt to configured additional keys (default False)
++        prepare		-- (ui) prepare for encryption (default False)
++        expect_sign	-- (ui) prepare for signing (default False)
++        compress	-- compress plaintext (default True)
++
++        Returns:
++        ciphertext	-- the encrypted data (or None if sink is given)
++        result		-- additional information about the encryption
++        sign_result	-- additional information about the signature(s)
++
++        Raises:
++        InvalidRecipients -- if encryption using a particular key failed
++        InvalidSigners	-- if signing using a particular key failed
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        ciphertext = sink if sink else Data()
++        flags = 0
++        flags |= always_trust * constants.ENCRYPT_ALWAYS_TRUST
++        flags |= (not add_encrypt_to) * constants.ENCRYPT_NO_ENCRYPT_TO
++        flags |= prepare * constants.ENCRYPT_PREPARE
++        flags |= expect_sign * constants.ENCRYPT_EXPECT_SIGN
++        flags |= (not compress) * constants.ENCRYPT_NO_COMPRESS
++
++        if passphrase != None:
++            old_pinentry_mode = self.pinentry_mode
++            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
++            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
++            def passphrase_cb(hint, desc, prev_bad, hook=None):
++                return passphrase
++            self.set_passphrase_cb(passphrase_cb)
++
++        try:
++            if sign:
++                self.op_encrypt_sign(recipients, flags, plaintext, ciphertext)
++            else:
++                self.op_encrypt(recipients, flags, plaintext, ciphertext)
++        except errors.GPGMEError as e:
++            if e.getcode() == errors.UNUSABLE_PUBKEY:
++                result = self.op_encrypt_result()
++                if result.invalid_recipients:
++                    raise errors.InvalidRecipients(result.invalid_recipients)
++            if e.getcode() == errors.UNUSABLE_SECKEY:
++                sig_result = self.op_sign_result()
++                if sig_result.invalid_signers:
++                    raise errors.InvalidSigners(sig_result.invalid_signers)
++            raise
++        finally:
++            if passphrase != None:
++                self.pinentry_mode = old_pinentry_mode
++                if old_passphrase_cb:
++                    self.set_passphrase_cb(*old_passphrase_cb[1:])
++
++        result = self.op_encrypt_result()
++        assert not result.invalid_recipients
++        sig_result = self.op_sign_result() if sign else None
++        assert not sig_result or not sig_result.invalid_signers
++
++        cipherbytes = None
++        if not sink:
++            ciphertext.seek(0, os.SEEK_SET)
++            cipherbytes = ciphertext.read()
++        return cipherbytes, result, sig_result
++
++    def decrypt(self, ciphertext, sink=None, passphrase=None, verify=True):
++        """Decrypt data
++
++        Decrypt the given ciphertext and verify any signatures.  If
++        VERIFY is an iterable of keys, the ciphertext must be signed
++        by all those keys, otherwise an error is raised.
++
++        If the ciphertext is symmetrically encrypted using a
++        passphrase, that passphrase can be given as parameter, using a
++        callback registered at the context, or out-of-band via
++        pinentry.
++
++        Keyword arguments:
++        sink		-- write result to sink instead of returning it
++        passphrase	-- for symmetric decryption
++        verify		-- check signatures (default True)
++
++        Returns:
++        plaintext	-- the decrypted data (or None if sink is given)
++        result		-- additional information about the decryption
++        verify_result	-- additional information about the signature(s)
++
++        Raises:
++        UnsupportedAlgorithm -- if an unsupported algorithm was used
++        BadSignatures	-- if a bad signature is encountered
++        MissingSignatures -- if expected signatures are missing or bad
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        plaintext = sink if sink else Data()
++
++        if passphrase != None:
++            old_pinentry_mode = self.pinentry_mode
++            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
++            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
++            def passphrase_cb(hint, desc, prev_bad, hook=None):
++                return passphrase
++            self.set_passphrase_cb(passphrase_cb)
++
++        try:
++            if verify:
++                self.op_decrypt_verify(ciphertext, plaintext)
++            else:
++                self.op_decrypt(ciphertext, plaintext)
++        finally:
++            if passphrase != None:
++                self.pinentry_mode = old_pinentry_mode
++                if old_passphrase_cb:
++                    self.set_passphrase_cb(*old_passphrase_cb[1:])
++
++        result = self.op_decrypt_result()
++        verify_result = self.op_verify_result() if verify else None
++        if result.unsupported_algorithm:
++            raise errors.UnsupportedAlgorithm(result.unsupported_algorithm)
++
++        if verify:
++            if any(s.status != errors.NO_ERROR
++                   for s in verify_result.signatures):
++                raise errors.BadSignatures(verify_result)
++
++        if verify and verify != True:
++            missing = list()
++            for key in verify:
++                ok = False
++                for subkey in key.subkeys:
++                    for sig in verify_result.signatures:
++                        if sig.summary & constants.SIGSUM_VALID == 0:
++                            continue
++                        if subkey.can_sign and subkey.fpr == sig.fpr:
++                            ok = True
++                            break
++                    if ok:
++                        break
++                if not ok:
++                    missing.append(key)
++            if missing:
++                raise errors.MissingSignatures(verify_result, missing)
++
++        plainbytes = None
++        if not sink:
++            plaintext.seek(0, os.SEEK_SET)
++            plainbytes = plaintext.read()
++        return plainbytes, result, verify_result
++
++    def sign(self, data, sink=None, mode=constants.SIG_MODE_NORMAL):
++        """Sign data
++
++        Sign the given data with either the configured default local
++        key, or the 'signers' keys of this context.
++
++        Keyword arguments:
++        mode		-- signature mode (default: normal, see below)
++        sink		-- write result to sink instead of returning it
++
++        Returns:
++        either
++          signed_data	-- encoded data and signature (normal mode)
++          signature	-- only the signature data (detached mode)
++          cleartext	-- data and signature as text (cleartext mode)
++            (or None if sink is given)
++        result		-- additional information about the signature(s)
++
++        Raises:
++        InvalidSigners	-- if signing using a particular key failed
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        signeddata = sink if sink else Data()
++
++        try:
++            self.op_sign(data, signeddata, mode)
++        except errors.GPGMEError as e:
++            if e.getcode() == errors.UNUSABLE_SECKEY:
++                result = self.op_sign_result()
++                if result.invalid_signers:
++                    raise errors.InvalidSigners(result.invalid_signers)
++            raise
++
++        result = self.op_sign_result()
++        assert not result.invalid_signers
++
++        signedbytes = None
++        if not sink:
++            signeddata.seek(0, os.SEEK_SET)
++            signedbytes = signeddata.read()
++        return signedbytes, result
++
++    def verify(self, signed_data, signature=None, sink=None, verify=[]):
++        """Verify signatures
++
++        Verify signatures over data.  If VERIFY is an iterable of
++        keys, the ciphertext must be signed by all those keys,
++        otherwise an error is raised.
++
++        Keyword arguments:
++        signature	-- detached signature data
++        sink		-- write result to sink instead of returning it
++
++        Returns:
++        data		-- the plain data
++            (or None if sink is given, or we verified a detached signature)
++        result		-- additional information about the signature(s)
++
++        Raises:
++        BadSignatures	-- if a bad signature is encountered
++        MissingSignatures -- if expected signatures are missing or bad
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        if signature:
++            # Detached signature, we don't return the plain text.
++            data = None
++        else:
++            data = sink if sink else Data()
++
++        if signature:
++            self.op_verify(signature, signed_data, None)
++        else:
++            self.op_verify(signed_data, None, data)
++
++        result = self.op_verify_result()
++        if any(s.status != errors.NO_ERROR for s in result.signatures):
++            raise errors.BadSignatures(result)
++
++        missing = list()
++        for key in verify:
++            ok = False
++            for subkey in key.subkeys:
++                for sig in result.signatures:
++                    if sig.summary & constants.SIGSUM_VALID == 0:
++                        continue
++                    if subkey.can_sign and subkey.fpr == sig.fpr:
++                        ok = True
++                        break
++                if ok:
++                    break
++            if not ok:
++                missing.append(key)
++        if missing:
++            raise errors.MissingSignatures(result, missing)
++
++        plainbytes = None
++        if data and not sink:
++            data.seek(0, os.SEEK_SET)
++            plainbytes = data.read()
++        return plainbytes, result
++
++    def keylist(self, pattern=None, secret=False,
++                mode=constants.keylist.mode.LOCAL,
++                source=None):
++        """List keys
++
++        Keyword arguments:
++        pattern	-- return keys matching pattern (default: all keys)
++        secret	-- return only secret keys (default: False)
++        mode    -- keylist mode (default: list local keys)
++        source  -- read keys from source instead from the keyring
++                       (all other options are ignored in this case)
++
++        Returns:
++                -- an iterator returning key objects
++
++        Raises:
++        GPGMEError	-- as signaled by the underlying library
++        """
++        if not source:
++            self.set_keylist_mode(mode)
++            self.op_keylist_start(pattern, secret)
++        else:
++            # Automatic wrapping of SOURCE is not possible here,
++            # because the object must not be deallocated until the
++            # iteration over the results ends.
++            if not isinstance(source, Data):
++                source = Data(file=source)
++            self.op_keylist_from_data_start(source, 0)
++
++        key = self.op_keylist_next()
++        while key:
++            yield key
++            key = self.op_keylist_next()
++        self.op_keylist_end()
++
++    def create_key(self, userid, algorithm=None, expires_in=0, expires=True,
++                   sign=False, encrypt=False, certify=False, authenticate=False,
++                   passphrase=None, force=False):
++        """Create a primary key
++
++        Create a primary key for the user id USERID.
++
++        ALGORITHM may be used to specify the public key encryption
++        algorithm for the new key.  By default, a reasonable default
++        is chosen.  You may use "future-default" to select an
++        algorithm that will be the default in a future implementation
++        of the engine.  ALGORITHM may be a string like "rsa", or
++        "rsa2048" to explicitly request an algorithm and a key size.
++
++        EXPIRES_IN specifies the expiration time of the key in number
++        of seconds since the keys creation.  By default, a reasonable
++        expiration time is chosen.  If you want to create a key that
++        does not expire, use the keyword argument EXPIRES.
++
++        SIGN, ENCRYPT, CERTIFY, and AUTHENTICATE can be used to
++        request the capabilities of the new key.  If you don't request
++        any, a reasonable set of capabilities is selected, and in case
++        of OpenPGP, a subkey with a reasonable set of capabilities is
++        created.
++
++        If PASSPHRASE is None (the default), then the key will not be
++        protected with a passphrase.  If PASSPHRASE is a string, it
++        will be used to protect the key.  If PASSPHRASE is True, the
++        passphrase must be supplied using a passphrase callback or
++        out-of-band with a pinentry.
++
++        Keyword arguments:
++        algorithm    -- public key algorithm, see above (default: reasonable)
++        expires_in   -- expiration time in seconds (default: reasonable)
++        expires      -- whether or not the key should expire (default: True)
++        sign         -- request the signing capability (see above)
++        encrypt      -- request the encryption capability (see above)
++        certify      -- request the certification capability (see above)
++        authenticate -- request the authentication capability (see above)
++        passphrase   -- protect the key with a passphrase (default: no passphrase)
++        force        -- force key creation even if a key with the same userid exists
++                                                          (default: False)
++
++        Returns:
++                     -- an object describing the result of the key creation
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        if util.is_a_string(passphrase):
++            old_pinentry_mode = self.pinentry_mode
++            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
++            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
++            def passphrase_cb(hint, desc, prev_bad, hook=None):
++                return passphrase
++            self.set_passphrase_cb(passphrase_cb)
++
++        try:
++            self.op_createkey(userid, algorithm,
++                              0, # reserved
++                              expires_in,
++                              None, # extrakey
++                              ((constants.create.SIGN if sign else 0)
++                               | (constants.create.ENCR if encrypt else 0)
++                               | (constants.create.CERT if certify else 0)
++                               | (constants.create.AUTH if authenticate else 0)
++                               | (constants.create.NOPASSWD if passphrase == None else 0)
++                               | (0 if expires else constants.create.NOEXPIRE)
++                               | (constants.create.FORCE if force else 0)))
++        finally:
++            if util.is_a_string(passphrase):
++                self.pinentry_mode = old_pinentry_mode
++                if old_passphrase_cb:
++                    self.set_passphrase_cb(*old_passphrase_cb[1:])
++
++        return self.op_genkey_result()
++
++    def create_subkey(self, key, algorithm=None, expires_in=0, expires=True,
++                      sign=False, encrypt=False, authenticate=False, passphrase=None):
++        """Create a subkey
++
++        Create a subkey for the given KEY.  As subkeys are a concept
++        of OpenPGP, calling this is only valid for the OpenPGP
++        protocol.
++
++        ALGORITHM may be used to specify the public key encryption
++        algorithm for the new subkey.  By default, a reasonable
++        default is chosen.  You may use "future-default" to select an
++        algorithm that will be the default in a future implementation
++        of the engine.  ALGORITHM may be a string like "rsa", or
++        "rsa2048" to explicitly request an algorithm and a key size.
++
++        EXPIRES_IN specifies the expiration time of the subkey in
++        number of seconds since the subkeys creation.  By default, a
++        reasonable expiration time is chosen.  If you want to create a
++        subkey that does not expire, use the keyword argument EXPIRES.
++
++        SIGN, ENCRYPT, and AUTHENTICATE can be used to request the
++        capabilities of the new subkey.  If you don't request any, an
++        encryption subkey is generated.
++
++        If PASSPHRASE is None (the default), then the subkey will not
++        be protected with a passphrase.  If PASSPHRASE is a string, it
++        will be used to protect the subkey.  If PASSPHRASE is True,
++        the passphrase must be supplied using a passphrase callback or
++        out-of-band with a pinentry.
++
++        Keyword arguments:
++        algorithm    -- public key algorithm, see above (default: reasonable)
++        expires_in   -- expiration time in seconds (default: reasonable)
++        expires      -- whether or not the subkey should expire (default: True)
++        sign         -- request the signing capability (see above)
++        encrypt      -- request the encryption capability (see above)
++        authenticate -- request the authentication capability (see above)
++        passphrase   -- protect the subkey with a passphrase (default: no passphrase)
++
++        Returns:
++                     -- an object describing the result of the subkey creation
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        if util.is_a_string(passphrase):
++            old_pinentry_mode = self.pinentry_mode
++            old_passphrase_cb = getattr(self, '_passphrase_cb', None)
++            self.pinentry_mode = constants.PINENTRY_MODE_LOOPBACK
++            def passphrase_cb(hint, desc, prev_bad, hook=None):
++                return passphrase
++            self.set_passphrase_cb(passphrase_cb)
++
++        try:
++            self.op_createsubkey(key, algorithm,
++                                 0, # reserved
++                                 expires_in,
++                                 ((constants.create.SIGN if sign else 0)
++                                  | (constants.create.ENCR if encrypt else 0)
++                                  | (constants.create.AUTH if authenticate else 0)
++                                  | (constants.create.NOPASSWD
++                                     if passphrase == None else 0)
++                                  | (0 if expires else constants.create.NOEXPIRE)))
++        finally:
++            if util.is_a_string(passphrase):
++                self.pinentry_mode = old_pinentry_mode
++                if old_passphrase_cb:
++                    self.set_passphrase_cb(*old_passphrase_cb[1:])
++
++        return self.op_genkey_result()
++
++    def key_add_uid(self, key, uid):
++        """Add a UID
++
++        Add the uid UID to the given KEY.  Calling this function is
++        only valid for the OpenPGP protocol.
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        self.op_adduid(key, uid, 0)
++
++    def key_revoke_uid(self, key, uid):
++        """Revoke a UID
++
++        Revoke the uid UID from the given KEY.  Calling this function
++        is only valid for the OpenPGP protocol.
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        self.op_revuid(key, uid, 0)
++
++    def key_sign(self, key, uids=None, expires_in=False, local=False):
++        """Sign a key
++
++        Sign a key with the current set of signing keys.  Calling this
++        function is only valid for the OpenPGP protocol.
++
++        If UIDS is None (the default), then all UIDs are signed.  If
++        it is a string, then only the matching UID is signed.  If it
++        is a list of strings, then all matching UIDs are signed.  Note
++        that a case-sensitive exact string comparison is done.
++
++        EXPIRES_IN specifies the expiration time of the signature in
++        seconds.  If EXPIRES_IN is False, the signature does not
++        expire.
++
++        Keyword arguments:
++        uids         -- user ids to sign, see above (default: sign all)
++        expires_in   -- validity period of the signature in seconds
++                                               (default: do not expire)
++        local        -- create a local, non-exportable signature
++                                               (default: False)
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        flags = 0
++        if uids == None or util.is_a_string(uids):
++            pass#through unchanged
++        else:
++            flags |= constants.keysign.LFSEP
++            uids = "\n".join(uids)
++
++        if not expires_in:
++            flags |= constants.keysign.NOEXPIRE
++
++        if local:
++            flags |= constants.keysign.LOCAL
++
++        self.op_keysign(key, uids, expires_in, flags)
++
++    def key_tofu_policy(self, key, policy):
++        """Set a keys' TOFU policy
++
++        Set the TOFU policy associated with KEY to POLICY.  Calling
++        this function is only valid for the OpenPGP protocol.
++
++        Raises:
++        GPGMEError   -- as signaled by the underlying library
++
++        """
++        self.op_tofu_policy(key, policy)
++
++    def assuan_transact(self, command,
++                        data_cb=None, inquire_cb=None, status_cb=None):
++        """Issue a raw assuan command
++
++        This function can be used to issue a raw assuan command to the
++        engine.
++
++        If command is a string or bytes, it will be used as-is.  If it
++        is an iterable of strings, it will be properly escaped and
++        joined into an well-formed assuan command.
++
++        Keyword arguments:
++        data_cb		-- a callback receiving data lines
++        inquire_cb	-- a callback providing more information
++        status_cb	-- a callback receiving status lines
++
++        Returns:
++        result		-- the result of command as GPGMEError
++
++        Raises:
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++
++        if util.is_a_string(command) or isinstance(command, bytes):
++            cmd = command
++        else:
++            cmd = " ".join(util.percent_escape(f) for f in command)
++
++        errptr = gpgme.new_gpgme_error_t_p()
++
++        err = gpgme.gpgme_op_assuan_transact_ext(
++            self.wrapped,
++            cmd,
++            (weakref.ref(self), data_cb) if data_cb else None,
++            (weakref.ref(self), inquire_cb) if inquire_cb else None,
++            (weakref.ref(self), status_cb) if status_cb else None,
++            errptr)
++
++        if self._callback_excinfo:
++            gpgme.gpg_raise_callback_exception(self)
++
++        errorcheck(err)
++
++        status = gpgme.gpgme_error_t_p_value(errptr)
++        gpgme.delete_gpgme_error_t_p(errptr)
++
++        return GPGMEError(status) if status != 0 else None
++
++    def interact(self, key, func, sink=None, flags=0, fnc_value=None):
++        """Interact with the engine
++
++        This method can be used to edit keys and cards interactively.
++        KEY is the key to edit, FUNC is called repeatedly with two
++        unicode arguments, 'keyword' and 'args'.  See the GPGME manual
++        for details.
++
++        Keyword arguments:
++        sink		-- if given, additional output is written here
++        flags		-- use constants.INTERACT_CARD to edit a card
++
++        Raises:
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        if key == None:
++            raise ValueError("First argument cannot be None")
++
++        if sink == None:
++            sink = Data()
++
++        if fnc_value:
++            opaquedata = (weakref.ref(self), func, fnc_value)
++        else:
++            opaquedata = (weakref.ref(self), func)
++
++        result = gpgme.gpgme_op_interact(self.wrapped, key, flags,
++                                         opaquedata, sink)
++        if self._callback_excinfo:
++            gpgme.gpg_raise_callback_exception(self)
++        errorcheck(result)
++
++    @property
++    def signers(self):
++        """Keys used for signing"""
++        return [self.signers_enum(i) for i in range(self.signers_count())]
++    @signers.setter
++    def signers(self, signers):
++        old = self.signers
++        self.signers_clear()
++        try:
++            for key in signers:
++                self.signers_add(key)
++        except:
++            self.signers = old
++            raise
++
++    @property
++    def pinentry_mode(self):
++        """Pinentry mode"""
++        return self.get_pinentry_mode()
++    @pinentry_mode.setter
++    def pinentry_mode(self, value):
++        self.set_pinentry_mode(value)
++
++    @property
++    def protocol(self):
++        """Protocol to use"""
++        return self.get_protocol()
++    @protocol.setter
++    def protocol(self, value):
++        errorcheck(gpgme.gpgme_engine_check_version(value))
++        self.set_protocol(value)
++
++    @property
++    def home_dir(self):
++        """Engine's home directory"""
++        return self.engine_info.home_dir
++    @home_dir.setter
++    def home_dir(self, value):
++        self.set_engine_info(self.protocol, home_dir=value)
++
++    _ctype = 'gpgme_ctx_t'
++    _cprefix = 'gpgme_'
++
++    def _errorcheck(self, name):
++        """This function should list all functions returning gpgme_error_t"""
++        # The list of functions is created using:
++        #
++        # $ grep '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
++        #   | grep -v _op_ | awk "/\(gpgme_ctx/ { printf (\"'%s',\\n\", \$2) } "
++        return ((name.startswith('gpgme_op_')
++                 and not name.endswith('_result'))
++                or name in {
++                    'gpgme_new',
++                    'gpgme_set_ctx_flag',
++                    'gpgme_set_protocol',
++                    'gpgme_set_sub_protocol',
++                    'gpgme_set_keylist_mode',
++                    'gpgme_set_pinentry_mode',
++                    'gpgme_set_locale',
++                    'gpgme_ctx_set_engine_info',
++                    'gpgme_signers_add',
++                    'gpgme_sig_notation_add',
++                    'gpgme_set_sender',
++                    'gpgme_cancel',
++                    'gpgme_cancel_async',
++                    'gpgme_get_key',
++                })
++
++    _boolean_properties = {'armor', 'textmode', 'offline'}
++
++    def __del__(self):
++        if not gpgme:
++            # At interpreter shutdown, gpgme is set to NONE.
++            return
++
++        self._free_passcb()
++        self._free_progresscb()
++        self._free_statuscb()
++        if self.own and self.wrapped and gpgme.gpgme_release:
++            gpgme.gpgme_release(self.wrapped)
++            self.wrapped = None
++
++    # Implement the context manager protocol.
++    def __enter__(self):
++        return self
++    def __exit__(self, type, value, tb):
++        self.__del__()
++
++    def op_keylist_all(self, *args, **kwargs):
++        self.op_keylist_start(*args, **kwargs)
++        key = self.op_keylist_next()
++        while key:
++            yield key
++            key = self.op_keylist_next()
++        self.op_keylist_end()
++
++    def op_keylist_next(self):
++        """Returns the next key in the list created
++        by a call to op_keylist_start().  The object returned
++        is of type Key."""
++        ptr = gpgme.new_gpgme_key_t_p()
++        try:
++            errorcheck(gpgme.gpgme_op_keylist_next(self.wrapped, ptr))
++            key = gpgme.gpgme_key_t_p_value(ptr)
++        except errors.GPGMEError as excp:
++            key = None
++            if excp.getcode() != errors.EOF:
++                raise excp
++        gpgme.delete_gpgme_key_t_p(ptr)
++        if key:
++            key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
++            return key
++
++    def get_key(self, fpr, secret=False):
++        """Get a key given a fingerprint
++
++        Keyword arguments:
++        secret		-- to request a secret key
++
++        Returns:
++                        -- the matching key
++
++        Raises:
++        KeyError	-- if the key was not found
++        GPGMEError	-- as signaled by the underlying library
++
++        """
++        ptr = gpgme.new_gpgme_key_t_p()
++
++        try:
++            errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
++        except errors.GPGMEError as e:
++            if e.getcode() == errors.EOF:
++                raise errors.KeyNotFound(fpr)
++            raise e
++
++        key = gpgme.gpgme_key_t_p_value(ptr)
++        gpgme.delete_gpgme_key_t_p(ptr)
++        assert key
++        key.__del__ = lambda self: gpgme.gpgme_key_unref(self)
++        return key
++
++    def op_trustlist_all(self, *args, **kwargs):
++        self.op_trustlist_start(*args, **kwargs)
++        trust = self.op_trustlist_next()
++        while trust:
++            yield trust
++            trust = self.op_trustlist_next()
++        self.op_trustlist_end()
++
++    def op_trustlist_next(self):
++        """Returns the next trust item in the list created
++        by a call to op_trustlist_start().  The object returned
++        is of type TrustItem."""
++        ptr = gpgme.new_gpgme_trust_item_t_p()
++        try:
++            errorcheck(gpgme.gpgme_op_trustlist_next(self.wrapped, ptr))
++            trust = gpgme.gpgme_trust_item_t_p_value(ptr)
++        except errors.GPGMEError as excp:
++            trust = None
++            if excp.getcode() != errors.EOF:
++                raise
++        gpgme.delete_gpgme_trust_item_t_p(ptr)
++        return trust
++
++    def set_passphrase_cb(self, func, hook=None):
++        """Sets the passphrase callback to the function specified by func.
++
++        When the system needs a passphrase, it will call func with three args:
++        hint, a string describing the key it needs the passphrase for;
++        desc, a string describing the passphrase it needs;
++        prev_bad, a boolean equal True if this is a call made after
++        unsuccessful previous attempt.
++
++        If hook has a value other than None it will be passed into the func
++        as a forth argument.
++
++        Please see the GPGME manual for more information.
++        """
++        if func == None:
++            hookdata = None
++        else:
++            if hook == None:
++                hookdata = (weakref.ref(self), func)
++            else:
++                hookdata = (weakref.ref(self), func, hook)
++        gpgme.gpg_set_passphrase_cb(self, hookdata)
++
++    def _free_passcb(self):
++        if gpgme.gpg_set_passphrase_cb:
++            self.set_passphrase_cb(None)
++
++    def set_progress_cb(self, func, hook=None):
++        """Sets the progress meter callback to the function specified by FUNC.
++        If FUNC is None, the callback will be cleared.
++
++        This function will be called to provide an interactive update
++        of the system's progress.  The function will be called with
++        three arguments, type, total, and current.  If HOOK is not
++        None, it will be supplied as fourth argument.
++
++        Please see the GPGME manual for more information.
++
++        """
++        if func == None:
++            hookdata = None
++        else:
++            if hook == None:
++                hookdata = (weakref.ref(self), func)
++            else:
++                hookdata = (weakref.ref(self), func, hook)
++        gpgme.gpg_set_progress_cb(self, hookdata)
++
++    def _free_progresscb(self):
++        if gpgme.gpg_set_progress_cb:
++            self.set_progress_cb(None)
++
++    def set_status_cb(self, func, hook=None):
++        """Sets the status callback to the function specified by FUNC.  If
++        FUNC is None, the callback will be cleared.
++
++        The function will be called with two arguments, keyword and
++        args.  If HOOK is not None, it will be supplied as third
++        argument.
++
++        Please see the GPGME manual for more information.
++
++        """
++        if func == None:
++            hookdata = None
++        else:
++            if hook == None:
++                hookdata = (weakref.ref(self), func)
++            else:
++                hookdata = (weakref.ref(self), func, hook)
++        gpgme.gpg_set_status_cb(self, hookdata)
++
++    def _free_statuscb(self):
++        if gpgme.gpg_set_status_cb:
++            self.set_status_cb(None)
++
++    @property
++    def engine_info(self):
++        """Configuration of the engine currently in use"""
++        p = self.protocol
++        infos = [i for i in self.get_engine_info() if i.protocol == p]
++        assert len(infos) == 1
++        return infos[0]
++
++    def get_engine_info(self):
++        """Get engine configuration
++
++        Returns information about all configured and installed
++        engines.
++
++        Returns:
++        infos		-- a list of engine infos
++
++        """
++        return gpgme.gpgme_ctx_get_engine_info(self.wrapped)
++
++    def set_engine_info(self, proto, file_name=None, home_dir=None):
++        """Change engine configuration
++
++        Changes the configuration of the crypto engine implementing
++        the protocol 'proto' for the context.
++
++        Keyword arguments:
++        file_name	-- engine program file name (unchanged if None)
++        home_dir	-- configuration directory (unchanged if None)
++
++        """
++        self.ctx_set_engine_info(proto, file_name, home_dir)
++
++    def wait(self, hang):
++        """Wait for asynchronous call to finish. Wait forever if hang is True.
++        Raises an exception on errors.
++
++        Please read the GPGME manual for more information.
++
++        """
++        ptr = gpgme.new_gpgme_error_t_p()
++        gpgme.gpgme_wait(self.wrapped, ptr, hang)
++        status = gpgme.gpgme_error_t_p_value(ptr)
++        gpgme.delete_gpgme_error_t_p(ptr)
++        errorcheck(status)
++
++    def op_edit(self, key, func, fnc_value, out):
++        """Start key editing using supplied callback function
++
++        Note: This interface is deprecated and will be removed with
++        GPGME 1.8.  Please use .interact instead.  Furthermore, we
++        implement this using gpgme_op_interact, so callbacks will get
++        called with string keywords instead of numeric status
++        messages.  Code that is using constants.STATUS_X or
++        constants.status.X will continue to work, whereas code using
++        magic numbers will break as a result.
++
++        """
++        warnings.warn("Call to deprecated method op_edit.",
++                      category=DeprecationWarning)
++        return self.interact(key, func, sink=out, fnc_value=fnc_value)
++
++
++class Data(GpgmeWrapper):
++    """Data buffer
++
++    A lot of data has to be exchanged between the user and the crypto
++    engine, like plaintext messages, ciphertext, signatures and
++    information about the keys.  The technical details about
++    exchanging the data information are completely abstracted by
++    GPGME.  The user provides and receives the data via `gpgme_data_t'
++    objects, regardless of the communication protocol between GPGME
++    and the crypto engine in use.
++
++    This Data class is the implementation of the GpgmeData objects.
++
++    Please see the information about __init__ for instantiation.
++
++    """
++
++    _ctype = 'gpgme_data_t'
++    _cprefix = 'gpgme_data_'
++
++    def _errorcheck(self, name):
++        """This function should list all functions returning gpgme_error_t"""
++        # This list is compiled using
++        #
++        # $ grep -v '^gpgme_error_t ' obj/lang/python/python3.5-gpg/gpgme.h \
++        #   | awk "/\(gpgme_data_t/ { printf (\"'%s',\\n\", \$2) } " | sed "s/'\\*/'/"
++        return name not in {
++            'gpgme_data_read',
++            'gpgme_data_write',
++            'gpgme_data_seek',
++            'gpgme_data_release',
++            'gpgme_data_release_and_get_mem',
++            'gpgme_data_get_encoding',
++            'gpgme_data_get_file_name',
++            'gpgme_data_identify',
++        }
++
++    def __init__(self, string=None, file=None, offset=None,
++                 length=None, cbs=None, copy=True):
++        """Initialize a new gpgme_data_t object.
++
++        If no args are specified, make it an empty object.
++
++        If string alone is specified, initialize it with the data
++        contained there.
++
++        If file, offset, and length are all specified, file must
++        be either a filename or a file-like object, and the object
++        will be initialized by reading the specified chunk from the file.
++
++        If cbs is specified, it MUST be a tuple of the form:
++
++        (read_cb, write_cb, seek_cb, release_cb[, hook])
++
++        where the first four items are functions implementing reading,
++        writing, seeking the data, and releasing any resources once
++        the data object is deallocated.  The functions must match the
++        following prototypes:
++
++            def read(amount, hook=None):
++                return <a b"bytes" object>
++
++            def write(data, hook=None):
++                return <the number of bytes written>
++
++            def seek(offset, whence, hook=None):
++                return <the new file position>
++
++            def release(hook=None):
++                <return value and exceptions are ignored>
++
++        The functions may be bound methods.  In that case, you can
++        simply use the 'self' reference instead of using a hook.
++
++        If file is specified without any other arguments, then
++        it must be a filename, and the object will be initialized from
++        that file.
++
++        """
++        super(Data, self).__init__(None)
++        self.data_cbs = None
++
++        if cbs != None:
++            self.new_from_cbs(*cbs)
++        elif string != None:
++            self.new_from_mem(string, copy)
++        elif file != None and offset != None and length != None:
++            self.new_from_filepart(file, offset, length)
++        elif file != None:
++            if util.is_a_string(file):
++                self.new_from_file(file, copy)
++            else:
++                self.new_from_fd(file)
++        else:
++            self.new()
++
++    def __del__(self):
++        if not gpgme:
++            # At interpreter shutdown, gpgme is set to NONE.
++            return
++
++        if self.wrapped != None and gpgme.gpgme_data_release:
++            gpgme.gpgme_data_release(self.wrapped)
++            if self._callback_excinfo:
++                gpgme.gpg_raise_callback_exception(self)
++            self.wrapped = None
++        self._free_datacbs()
++
++    # Implement the context manager protocol.
++    def __enter__(self):
++        return self
++    def __exit__(self, type, value, tb):
++        self.__del__()
++
++    def _free_datacbs(self):
++        self._data_cbs = None
++
++    def new(self):
++        tmp = gpgme.new_gpgme_data_t_p()
++        errorcheck(gpgme.gpgme_data_new(tmp))
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_mem(self, string, copy=True):
++        tmp = gpgme.new_gpgme_data_t_p()
++        errorcheck(gpgme.gpgme_data_new_from_mem(tmp,string,len(string),copy))
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_file(self, filename, copy=True):
++        tmp = gpgme.new_gpgme_data_t_p()
++        try:
++            errorcheck(gpgme.gpgme_data_new_from_file(tmp, filename, copy))
++        except errors.GPGMEError as e:
++            if e.getcode() == errors.INV_VALUE and not copy:
++                raise ValueError("delayed reads are not yet supported")
++            else:
++                raise e
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_cbs(self, read_cb, write_cb, seek_cb, release_cb, hook=None):
++        tmp = gpgme.new_gpgme_data_t_p()
++        if hook != None:
++            hookdata = (weakref.ref(self),
++                        read_cb, write_cb, seek_cb, release_cb, hook)
++        else:
++            hookdata = (weakref.ref(self),
++                        read_cb, write_cb, seek_cb, release_cb)
++        gpgme.gpg_data_new_from_cbs(self, hookdata, tmp)
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_filepart(self, file, offset, length):
++        """This wraps the GPGME gpgme_data_new_from_filepart() function.
++        The argument "file" may be:
++
++        * a string specifying a file name, or
++        * a file-like object supporting the fileno() and the mode attribute.
++
++        """
++
++        tmp = gpgme.new_gpgme_data_t_p()
++        filename = None
++        fp = None
++
++        if util.is_a_string(file):
++            filename = file
++        else:
++            fp = gpgme.fdopen(file.fileno(), file.mode)
++            if fp == None:
++                raise ValueError("Failed to open file from %s arg %s" % \
++                      (str(type(file)), str(file)))
++
++        errorcheck(gpgme.gpgme_data_new_from_filepart(tmp, filename, fp,
++                                                      offset, length))
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_fd(self, file):
++        """This wraps the GPGME gpgme_data_new_from_fd() function.  The
++        argument "file" must be a file-like object, supporting the
++        fileno() method.
++
++        """
++        tmp = gpgme.new_gpgme_data_t_p()
++        errorcheck(gpgme.gpgme_data_new_from_fd(tmp, file.fileno()))
++        self.wrapped = gpgme.gpgme_data_t_p_value(tmp)
++        gpgme.delete_gpgme_data_t_p(tmp)
++
++    def new_from_stream(self, file):
++        """This wrap around gpgme_data_new_from_stream is an alias for
++        new_from_fd() method since in python there's not difference
++        between file stream and file descriptor"""
++        self.new_from_fd(file)
++
++    def write(self, buffer):
++        """Write buffer given as string or bytes.
++
++        If a string is given, it is implicitly encoded using UTF-8."""
++        written = gpgme.gpgme_data_write(self.wrapped, buffer)
++        if written < 0:
++            if self._callback_excinfo:
++                gpgme.gpg_raise_callback_exception(self)
++            else:
++                raise GPGMEError.fromSyserror()
++        return written
++
++    def read(self, size = -1):
++        """Read at most size bytes, returned as bytes.
++
++        If the size argument is negative or omitted, read until EOF is reached.
++
++        Returns the data read, or the empty string if there was no data
++        to read before EOF was reached."""
++
++        if size == 0:
++            return ''
++
++        if size > 0:
++            try:
++                result = gpgme.gpgme_data_read(self.wrapped, size)
++            except:
++                if self._callback_excinfo:
++                    gpgme.gpg_raise_callback_exception(self)
++                else:
++                    raise
++            return result
++        else:
++            chunks = []
++            while True:
++                try:
++                    result = gpgme.gpgme_data_read(self.wrapped, 4096)
++                except:
++                    if self._callback_excinfo:
++                        gpgme.gpg_raise_callback_exception(self)
++                    else:
++                        raise
++                if len(result) == 0:
++                    break
++                chunks.append(result)
++            return b''.join(chunks)
++
++def pubkey_algo_string(subkey):
++    """Return short algorithm string
++
++    Return a public key algorithm string (e.g. "rsa2048") for a given
++    SUBKEY.
++
++    Returns:
++    algo      - a string
++
++    """
++    return gpgme.gpgme_pubkey_algo_string(subkey)
++
++def pubkey_algo_name(algo):
++    """Return name of public key algorithm
++
++    Return the name of the public key algorithm for a given numeric
++    algorithm id ALGO (cf. RFC4880).
++
++    Returns:
++    algo      - a string
++
++    """
++    return gpgme.gpgme_pubkey_algo_name(algo)
++
++def hash_algo_name(algo):
++    """Return name of hash algorithm
++
++    Return the name of the hash algorithm for a given numeric
++    algorithm id ALGO (cf. RFC4880).
++
++    Returns:
++    algo      - a string
++
++    """
++    return gpgme.gpgme_hash_algo_name(algo)
++
++def get_protocol_name(proto):
++    """Get protocol description
++
++    Get the string describing protocol PROTO.
++
++    Returns:
++    proto     - a string
++
++    """
++    return gpgme.gpgme_get_protocol_name(proto)
++
++def addrspec_from_uid(uid):
++    """Return the address spec
++
++    Return the addr-spec (cf. RFC2822 section 4.3) from a user id UID.
++
++    Returns:
++    addr_spec - a string
++
++    """
++    return gpgme.gpgme_addrspec_from_uid(uid)
++
++def check_version(version=None):
++    return gpgme.gpgme_check_version(version)
++
++# check_version also makes sure that several subsystems are properly
++# initialized, and it must be run at least once before invoking any
++# other function.  We do it here so that the user does not have to do
++# it unless she really wants to check for a certain version.
++check_version()
++
++def engine_check_version (proto):
++    try:
++        errorcheck(gpgme.gpgme_engine_check_version(proto))
++        return True
++    except errors.GPGMEError:
++        return False
++
++def get_engine_info():
++    ptr = gpgme.new_gpgme_engine_info_t_p()
++    try:
++        errorcheck(gpgme.gpgme_get_engine_info(ptr))
++        info = gpgme.gpgme_engine_info_t_p_value(ptr)
++    except errors.GPGMEError:
++        info = None
++    gpgme.delete_gpgme_engine_info_t_p(ptr)
++    return info
++
++def set_engine_info(proto, file_name, home_dir=None):
++    """Changes the default configuration of the crypto engine implementing
++    the protocol 'proto'. 'file_name' is the file name of
++    the executable program implementing this protocol. 'home_dir' is the
++    directory name of the configuration directory (engine's default is
++    used if omitted)."""
++    errorcheck(gpgme.gpgme_set_engine_info(proto, file_name, home_dir))
++
++def set_locale(category, value):
++    """Sets the default locale used by contexts"""
++    errorcheck(gpgme.gpgme_set_locale(None, category, value))
++
++def wait(hang):
++    """Wait for asynchronous call on any Context  to finish.
++    Wait forever if hang is True.
++
++    For finished anynch calls it returns a tuple (status, context):
++        status  - status return by asnynchronous call.
++        context - context which caused this call to return.
++
++    Please read the GPGME manual of more information."""
++    ptr = gpgme.new_gpgme_error_t_p()
++    context = gpgme.gpgme_wait(None, ptr, hang)
++    status = gpgme.gpgme_error_t_p_value(ptr)
++    gpgme.delete_gpgme_error_t_p(ptr)
++    if context == None:
++        errorcheck(status)
++    else:
++        context = Context(context)
++    return (status, context)
+diff --git a/lang/python/src/errors.py b/lang/python/src/errors.py
+new file mode 100644
+index 0000000..1ce139e
+--- /dev/null
++++ b/lang/python/src/errors.py
+@@ -0,0 +1,128 @@
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++from . import gpgme
++from . import util
++
++# To appease static analysis tools, we define some constants here.
++# They are overwritten with the proper values by process_constants.
++NO_ERROR = None
++EOF = None
++
++util.process_constants('GPG_ERR_', globals())
++del util
++
++class GpgError(Exception):
++    pass
++
++class GPGMEError(GpgError):
++    def __init__(self, error = None, message = None):
++        self.error = error
++        self.message = message
++
++    @classmethod
++    def fromSyserror(cls):
++        return cls(gpgme.gpgme_err_code_from_syserror())
++
++    def getstring(self):
++        message = "%s: %s" % (gpgme.gpgme_strsource(self.error),
++                              gpgme.gpgme_strerror(self.error))
++        if self.message != None:
++            message = "%s: %s" % (self.message, message)
++        return message
++
++    def getcode(self):
++        return gpgme.gpgme_err_code(self.error)
++
++    def getsource(self):
++        return gpgme.gpgme_err_source(self.error)
++
++    def __str__(self):
++        return self.getstring()
++
++def errorcheck(retval, extradata = None):
++    if retval:
++        raise GPGMEError(retval, extradata)
++
++class KeyNotFound(GPGMEError, KeyError):
++    """Raised if a key was not found
++
++    GPGME indicates this condition with EOF, which is not very
++    idiomatic.  We raise this error that is both a GPGMEError
++    indicating EOF, and a KeyError.
++
++    """
++    def __init__(self, keystr):
++        self.keystr = keystr
++        GPGMEError.__init__(self, EOF)
++    def __str__(self):
++        return self.keystr
++
++# These errors are raised in the idiomatic interface code.
++
++class EncryptionError(GpgError):
++    pass
++
++class InvalidRecipients(EncryptionError):
++    def __init__(self, recipients):
++        self.recipients = recipients
++    def __str__(self):
++        return ", ".join("{}: {}".format(r.fpr,
++                                         gpgme.gpgme_strerror(r.reason))
++                         for r in self.recipients)
++
++class DeryptionError(GpgError):
++    pass
++
++class UnsupportedAlgorithm(DeryptionError):
++    def __init__(self, algorithm):
++        self.algorithm = algorithm
++    def __str__(self):
++        return self.algorithm
++
++class SigningError(GpgError):
++    pass
++
++class InvalidSigners(SigningError):
++    def __init__(self, signers):
++        self.signers = signers
++    def __str__(self):
++        return ", ".join("{}: {}".format(s.fpr,
++                                         gpgme.gpgme_strerror(s.reason))
++                         for s in self.signers)
++
++class VerificationError(GpgError):
++    pass
++
++class BadSignatures(VerificationError):
++    def __init__(self, result):
++        self.result = result
++    def __str__(self):
++        return ", ".join("{}: {}".format(s.fpr,
++                                         gpgme.gpgme_strerror(s.status))
++                         for s in self.result.signatures
++                         if s.status != NO_ERROR)
++
++class MissingSignatures(VerificationError):
++    def __init__(self, result, missing):
++        self.result = result
++        self.missing = missing
++    def __str__(self):
++        return ", ".join(k.subkeys[0].fpr for k in self.missing)
+diff --git a/lang/python/src/results.py b/lang/python/src/results.py
+new file mode 100644
+index 0000000..46ebeec
+--- /dev/null
++++ b/lang/python/src/results.py
+@@ -0,0 +1,118 @@
++# Robust result objects
++#
++# Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++"""Robust result objects
++
++Results returned by the underlying library are fragile, i.e. they are
++only valid until the next operation is performed in the context.
++
++We cannot arbitrarily constrain the lifetime of Python objects, we
++therefore create deep copies of the results.
++
++"""
++
++class Result(object):
++    """Result object
++
++    Describes the result of an operation.
++
++    """
++
++    """Convert to types"""
++    _type = {}
++
++    """Map functions over list attributes"""
++    _map = {}
++
++    """Automatically copy unless blacklisted"""
++    _blacklist = {
++        'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown',
++    }
++    def __init__(self, fragile):
++        for key, func in self._type.items():
++            if hasattr(fragile, key):
++                setattr(self, key, func(getattr(fragile, key)))
++
++        for key, func in self._map.items():
++            if hasattr(fragile, key):
++                setattr(self, key, list(map(func, getattr(fragile, key))))
++
++        for key in dir(fragile):
++            if key.startswith('_') or key in self._blacklist:
++                continue
++            if hasattr(self, key):
++                continue
++
++            setattr(self, key, getattr(fragile, key))
++
++    def __repr__(self):
++        return '{}({})'.format(
++            self.__class__.__name__,
++            ', '.join('{}={!r}'.format(k, getattr(self, k))
++                      for k in dir(self) if not k.startswith('_')))
++
++class InvalidKey(Result):
++    pass
++
++class EncryptResult(Result):
++    _map = dict(invalid_recipients=InvalidKey)
++
++class Recipient(Result):
++    pass
++
++class DecryptResult(Result):
++    _type = dict(wrong_key_usage=bool)
++    _map = dict(recipients=Recipient)
++
++class NewSignature(Result):
++    pass
++
++class SignResult(Result):
++    _map = dict(invalid_signers=InvalidKey, signatures=NewSignature)
++
++class Notation(Result):
++    pass
++
++class Signature(Result):
++    _type = dict(wrong_key_usage=bool, chain_model=bool)
++    _map = dict(notations=Notation)
++
++class VerifyResult(Result):
++    _map = dict(signatures=Signature)
++
++class ImportStatus(Result):
++    pass
++
++class ImportResult(Result):
++    _map = dict(imports=ImportStatus)
++
++class GenkeyResult(Result):
++    _type = dict(primary=bool, sub=bool)
++
++class KeylistResult(Result):
++    _type = dict(truncated=bool)
++
++class VFSMountResult(Result):
++    pass
++
++class EngineInfo(Result):
++    pass
+diff --git a/lang/python/src/util.py b/lang/python/src/util.py
+new file mode 100644
+index 0000000..e4fca4c
+--- /dev/null
++++ b/lang/python/src/util.py
+@@ -0,0 +1,53 @@
++# Copyright (C) 2016 g10 Code GmbH
++# Copyright (C) 2004,2008 Igor Belyi <belyi at users.sourceforge.net>
++# Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++#
++#    This library 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.
++#
++#    This library 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 library; if not, write to the Free Software
++#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function, unicode_literals
++del absolute_import, print_function, unicode_literals
++
++import sys
++
++def process_constants(prefix, scope):
++    """Called by the constant modules to load up the constants from the C
++    library starting with PREFIX.  Matching constants will be inserted
++    into SCOPE with PREFIX stripped from the names.  Returns the names
++    of inserted constants.
++
++    """
++    from . import gpgme
++    index = len(prefix)
++    constants = {identifier[index:]: getattr(gpgme, identifier)
++                 for identifier in dir(gpgme)
++                 if identifier.startswith(prefix)}
++    scope.update(constants)
++    return list(constants.keys())
++
++def percent_escape(s):
++    return ''.join(
++        '%{0:2x}'.format(ord(c))
++        if c == '+' or c == '"' or c == '%' or ord(c) <= 0x20 else c
++        for c in s)
++
++# Python2/3 compatibility
++if sys.version_info[0] == 3:
++    # Python3
++    def is_a_string(x):
++        return isinstance(x, str)
++else:
++    # Python2
++    def is_a_string(x):
++        return isinstance(x, basestring)
+diff --git a/lang/python/version.py.in b/lang/python/version.py.in
+new file mode 100644
+index 0000000..1a1baf0
+--- /dev/null
++++ b/lang/python/version.py.in
+@@ -0,0 +1,68 @@
++# Copyright (C) 2016 g10 Code GmbH
++# Copyright (C) 2015 Ben McGinnes <ben at adversary.org>
++# Copyright (C) 2004 Igor Belyi <belyi at users.sourceforge.net>
++#
++# This library 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.
++#
++# This library 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 library; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
++
++from __future__ import absolute_import, print_function
++del absolute_import, print_function
++
++from . import gpgme
++
++productname = 'gpg'
++versionstr = "@VERSION@"
++gpgme_versionstr = gpgme.GPGME_VERSION
++in_tree_build = bool(gpgme.cvar.gpg_in_tree_build)
++
++versionlist = versionstr.split(".")
++major = versionlist[0]
++minor = versionlist[1]
++patch = versionlist[2]
++
++copyright = """\
++Copyright (C) 2016 g10 Code GmbH
++Copyright (C) 2015 Ben McGinnes
++Copyright (C) 2014-2015 Martin Albrecht
++Copyright (C) 2004-2008 Igor Belyi
++Copyright (C) 2002 John Goerzen"""
++
++author = "The GnuPG hackers"
++author_email = "gnupg-devel at gnupg.org"
++
++description = "Python support for GPGME GnuPG cryptography library"
++homepage = "https://gnupg.org"
++
++license = """Copyright (C) 2016 g10 Code GmbH
++Copyright (C) 2015 Ben McGinnes <ben at adversary.org>
++Copyright (C) 2014, 2015 Martin Albrecht <martinralbrecht at googlemail.com>
++Copyright (C) 2004, 2008 Igor Belyi <belyi at users.sourceforge.net>
++Copyright (C) 2002 John Goerzen <jgoerzen at complete.org>
++
++This library 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.
++
++This library 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 library; if not, write to the Free Software
++Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA"""
++
++# Interface hygiene.  Keep this at the end.
++del gpgme
diff --git a/debian/patches/0008-python-support-.pydistutils.cfg-mode.patch b/debian/patches/0008-python-support-.pydistutils.cfg-mode.patch
new file mode 100644
index 0000000..e2c0d97
--- /dev/null
+++ b/debian/patches/0008-python-support-.pydistutils.cfg-mode.patch
@@ -0,0 +1,101 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Fri, 7 Apr 2017 17:31:47 +0300
+Subject: python: support .pydistutils.cfg mode
+
+* lang/python/setup.py.in: Do not parse arguments.
+
+--
+
+The distutils settings can come from either command-line or
+configuration file. Parsing parameters is not working in all cases.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 365c649ad073f2697438dc014160943ae31a1447)
+---
+ lang/python/setup.py.in | 25 ++++++++++---------------
+ 1 file changed, 10 insertions(+), 15 deletions(-)
+
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index 5d94c70..e50971c 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -19,18 +19,12 @@
+ #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ 
+ from distutils.core import setup, Extension
+-import argparse
+ import os, os.path, sys
+ import glob
+ import re
+ import shutil
+ import subprocess
+ 
+-# We parse a subset of the arguments.
+-parser = argparse.ArgumentParser(add_help=False)
+-parser.add_argument('--build-base', default='')
+-options, _ = parser.parse_known_args()
+-
+ # Out-of-tree build of the gpg bindings.
+ gpg_error_config = ["gpg-error-config"]
+ gpgme_config_flags = ["--thread=pthread"]
+@@ -142,8 +136,6 @@ if uname_s.startswith("MINGW32"):
+ 
+ def in_srcdir(name):
+     return os.path.join(os.environ.get("srcdir", ""), name)
+-def in_build_base(name):
+-    return os.path.join(options.build_base, name)
+ def up_to_date(source, target):
+     return (os.path.exists(target)
+             and os.path.getmtime(source) <= os.path.getmtime(target))
+@@ -190,6 +182,9 @@ class BuildExtFirstHack(build):
+                     continue
+                 sink.write(rewrite_re.sub(r'%constant long \1 = \1;'+'\n', line.strip()))
+ 
++    def _in_build_base(self, name):
++        return os.path.join(self.build_base, name)
++
+     def _generate(self):
+         print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
+ 
+@@ -197,18 +192,18 @@ class BuildExtFirstHack(build):
+         if not os.path.exists(self.build_base):
+             os.makedirs(self.build_base)
+ 
+-        self._generate_gpgme_h(gpgme_h, in_build_base("gpgme.h"))
+-        self._generate_errors_i(gpg_error_h, in_build_base("errors.i"))
++        self._generate_gpgme_h(gpgme_h, self._in_build_base("gpgme.h"))
++        self._generate_errors_i(gpg_error_h, self._in_build_base("errors.i"))
+ 
+         # Keep timestamp to avoid rebuild
+-        for source, target in ((gpgme_h, in_build_base("gpgme.h")),
+-                               (gpg_error_h, in_build_base("errors.i"))):
++        for source, target in ((gpgme_h, self._in_build_base("gpgme.h")),
++                               (gpg_error_h, self._in_build_base("errors.i"))):
+             if not up_to_date(source, target):
+                 shutil.copystat(source, target)
+ 
+         # Copy due to http://bugs.python.org/issue2624
+         # Avoid creating in srcdir
+-        for source, target in ((in_srcdir(n), in_build_base(n))
++        for source, target in ((in_srcdir(n), self._in_build_base(n))
+                                for n in ('gpgme.i', 'helpers.c', 'private.h', 'helpers.h')):
+             if not up_to_date(source, target):
+                 shutil.copy2(source, target)
+@@ -221,7 +216,7 @@ class BuildExtFirstHack(build):
+     def run(self):
+         self._generate()
+ 
+-        swig_sources.append(os.path.join(self.build_base, 'gpgme.i'))
++        swig_sources.extend((self._in_build_base('gpgme.i'), self._in_build_base('helpers.c')))
+         swig_opts.extend(['-I' + self.build_base,
+                           '-outdir', os.path.join(self.build_lib, 'gpg')])
+         include_dirs.append(self.build_base)
+@@ -230,7 +225,7 @@ class BuildExtFirstHack(build):
+         build.run(self)
+ 
+ py3 = [] if sys.version_info.major < 3 else ['-py3']
+-swig_sources = [in_build_base('helpers.c')]
++swig_sources = []
+ swig_opts = ['-threads'] + py3 + extra_swig_opts
+ swige = Extension("gpg._gpgme",
+                   sources = swig_sources,
diff --git a/debian/patches/0009-tests-Do-not-use-check-local-magic-as-dependency.patch b/debian/patches/0009-tests-Do-not-use-check-local-magic-as-dependency.patch
new file mode 100644
index 0000000..a640ae5
--- /dev/null
+++ b/debian/patches/0009-tests-Do-not-use-check-local-magic-as-dependency.patch
@@ -0,0 +1,98 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Fri, 7 Apr 2017 17:32:18 +0300
+Subject: tests: Do not use check-local magic as dependency
+
+* tests/gpg/Makefile.am: Use BUILT_SOURCES instead of check-local
+and initial.test.
+* lang/qt/tests/Makefile.am: Ditto.
+
+--
+
+This fixes "make dist" failure when source tree is clean:
+  git clean -dxf
+  autoreconf -ivf
+  ./configure
+  make dist
+
+BUILT_SOURCES should be used when file as generated without explicit
+dependency. The check-local is all-am dependency, this means that it
+will be resolved also in "make dist".
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit ebefc6cbf937d14ced65f7ded79c4ba901507d23)
+---
+ lang/qt/tests/Makefile.am | 12 +++---------
+ tests/gpg/Makefile.am     |  9 ++-------
+ 2 files changed, 5 insertions(+), 16 deletions(-)
+
+diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
+index 93dce07..fb45eec 100644
+--- a/lang/qt/tests/Makefile.am
++++ b/lang/qt/tests/Makefile.am
+@@ -43,12 +43,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
+               -I$(top_srcdir)/lang/qt/src \
+               -DTOP_SRCDIR="$(top_srcdir)"
+ 
+-check-local: ./pubring-stamp
+-
+-# To guarantee that check-local is run before any tests we
+-# add this dependency:
+-initial.test : check-local
+-
+ support_src = t-support.h t-support.cpp
+ 
+ t_keylist_SOURCES = t-keylist.cpp $(support_src)
+@@ -64,7 +58,7 @@ run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp
+ 
+ nodist_t_keylist_SOURCES = $(moc_files)
+ 
+-BUILT_SOURCES = $(moc_files)
++BUILT_SOURCES = $(moc_files) pubring-stamp
+ 
+ noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt \
+     run-keyformailboxjob t-wkspublish t-verify t-various t-config
+@@ -79,7 +73,7 @@ clean-local:
+ 
+ export GNUPGHOME := $(abs_builddir)
+ 
+-./pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc \
++pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc \
+ 	             $(top_srcdir)/tests/gpg/secdemo.asc
+ 	echo "ignore-invalid-option allow-loopback-pinentry" > $(abs_builddir)/gpg-agent.conf
+ 	echo "allow-loopback-pinentry" >> gpg-agent.conf
+@@ -90,7 +84,7 @@ export GNUPGHOME := $(abs_builddir)
+ 	$(GPG) --no-permission-warning \
+ 		   --passphrase "abc" \
+            --import $(top_srcdir)/tests/gpg/secdemo.asc
+-	touch ./pubring-stamp
++	touch pubring-stamp
+ 
+ .cpp.moc:
+ 	$(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
+index 8e26a92..4cba303 100644
+--- a/tests/gpg/Makefile.am
++++ b/tests/gpg/Makefile.am
+@@ -60,6 +60,8 @@ EXTRA_DIST = initial.test final.test \
+         pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \
+ 	geheim.txt pubkey-1.asc seckey-1.asc pinentry $(private_keys)
+ 
++BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
++           private-keys-v1.d/gpg-sample.stamp
+ AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@
+ AM_LDFLAGS = -no-install
+ LDADD = ../../src/libgpgme.la
+@@ -82,13 +84,6 @@ clean-local:
+ 	-$(top_srcdir)/tests/start-stop-agent --stop
+ 	-rm -fR private-keys-v1.d
+ 
+-check-local: ./gpg.conf ./gpg-agent.conf ./pubring-stamp \
+-           ./private-keys-v1.d/gpg-sample.stamp
+-
+-# To guarantee that check-local is run before any tests we
+-# add this dependency:
+-initial.test : check-local
+-
+ export GNUPGHOME := $(abs_builddir)
+ 
+ export GPG_AGENT_INFO :=
diff --git a/debian/patches/0010-python-Remove-usage-of-PYTHON_VERSIONS.patch b/debian/patches/0010-python-Remove-usage-of-PYTHON_VERSIONS.patch
new file mode 100644
index 0000000..dac8257
--- /dev/null
+++ b/debian/patches/0010-python-Remove-usage-of-PYTHON_VERSIONS.patch
@@ -0,0 +1,111 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Sat, 8 Apr 2017 16:34:30 +0300
+Subject: python: Remove usage of PYTHON_VERSIONS
+
+* configure.ac: Remove PYTHON_VERSIONS subst.
+* lang/python/Makefile.am: Use basename of python as builddir prefix.
+* lang/python/tests/run-tests.py: Likewise.
+
+--
+
+Two variables needs be at sync PYTHONS and PYTHON_VERSIONS, these may go
+out of sync in some cases, for example in Gentoo where default python is
+3.4 we get:
+
+PYTHON='/usr/bin/python2'
+PYTHONS='/usr/bin/python /usr/bin/python2'
+PYTHON_VERSIONS='2.7 3.4'
+
+We can use the basename of the python interpreter to achieve similar
+effect without having to sync indexes between these two variables.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 25e6444b3f4601c7821beab06bc4520deacb007b)
+---
+ configure.ac                   |  1 -
+ lang/python/Makefile.am        | 23 +++++++++++------------
+ lang/python/tests/run-tests.py |  4 ++--
+ 3 files changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index e77cc23..36c547b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -471,7 +471,6 @@ if test "$found_py" = "1" -o "$found_py2" = "1" -o "$found_py3" = "1"; then
+ 	fi
+ 
+ 	AC_SUBST(PYTHONS, $PYTHONS)
+-	AC_SUBST(PYTHON_VERSIONS, $PYTHON_VERSIONS)
+     fi
+ fi
+ 
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index 4ebd214..90075f7 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -38,12 +38,11 @@ copystamp:
+ 	touch $@
+ 
+ all-local: copystamp
+-	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+-	  PYTHON="$$1" ; shift ; \
++	set -e ; for PYTHON in $(PYTHONS); do \
+ 	  CFLAGS="$(CFLAGS)" \
+ 	  srcdir="$(srcdir)" \
+ 	  top_builddir="$(top_builddir)" \
+-	    $$PYTHON setup.py build --verbose --build-base=python$${VERSION}-gpg ; \
++	    $$PYTHON setup.py build --verbose --build-base="$$(basename "$${PYTHON}")-gpg" ; \
+ 	done
+ 
+ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+@@ -76,26 +75,26 @@ CLEANFILES = copystamp \
+ # permissions.
+ clean-local:
+ 	rm -rf -- build
+-	for VERSION in $(PYTHON_VERSIONS); do \
+-	  find python$${VERSION}-gpg* -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+-	  rm -rf -- python$${VERSION}-gpg* ; \
++	for PYTHON in $(PYTHONS); do \
++	  find "$$(basename "$${PYTHON}")-gpg" -type d ! -perm -200 -exec chmod u+w {} ';' ; \
++	  rm -rf -- "$$(basename "$${PYTHON}")-gpg" ; \
+ 	done
+ 
+ install-exec-local:
+-	set -e ; set $(PYTHONS); for VERSION in $(PYTHON_VERSIONS); do \
+-	  PYTHON="$$1" ; shift ; \
++	set -e ; for PYTHON in $(PYTHONS); do \
+ 	  srcdir="$(srcdir)" \
+ 	  top_builddir="$(top_builddir)" \
+ 	  $$PYTHON setup.py \
+ 	  build \
+-	  --build-base=python$${VERSION}-gpg \
++	  --build-base="$$(basename "$${PYTHON}")-gpg" \
+ 	  install \
+ 	  --prefix "$(DESTDIR)$(prefix)" \
+ 	  --verbose ; \
+ 	done
+ 
+ uninstall-local:
+-	GV=$$(echo $(VERSION) | tr - _); for PV in $(PYTHON_VERSIONS); do \
+-	  rm -rf -- "$(DESTDIR)$(prefix)"/lib*/python$$PV/site-packages/gpg \
+-"$(DESTDIR)$(prefix)"/lib*/python$$PV/site-packages/gpg-$$GV-py$$PV.egg-info ; \
++	GV=$$(echo $(VERSION) | tr - _); for PYTHON in $(PYTHONS); do \
++	  PLATLIB="$(prefix)/$$("$${PYTHON}" -c 'import sysconfig, os; print(os.path.relpath(sysconfig.get_path("platlib"), sysconfig.get_config_var("prefix")))')" ; \
++	  rm -rf -- "$(DESTDIR)$${PLATLIB}/gpg" \
++		"$(DESTDIR)$${PLATLIB}"/gpg-$$GV-py*.egg-info ; \
+ 	done
+diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py
+index 9721997..5d5294a 100644
+--- a/lang/python/tests/run-tests.py
++++ b/lang/python/tests/run-tests.py
+@@ -70,8 +70,8 @@ for interpreter in args.interpreters:
+         [interpreter, "-c", "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"]).strip().decode()
+ 
+     pattern = os.path.join(args.builddir, "..",
+-                           "python{0}-gpg".format(version),
+-                           "lib*"+version)
++                           "{0}-gpg".format(os.path.basename(interpreter)),
++                           "lib*")
+     builddirs = glob.glob(pattern)
+     if len(builddirs) == 0:
+         sys.exit("Build directory matching {0!r} not found.".format(pattern))
diff --git a/debian/patches/0011-python-Remove-unneeded-stats-copy.patch b/debian/patches/0011-python-Remove-unneeded-stats-copy.patch
new file mode 100644
index 0000000..8990d90
--- /dev/null
+++ b/debian/patches/0011-python-Remove-unneeded-stats-copy.patch
@@ -0,0 +1,30 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Sat, 8 Apr 2017 16:34:31 +0300
+Subject: python: Remove unneeded stats copy
+
+* lang/python/setup.py.in: errors.i, gpgme.h are generated and always
+newer than the original.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit df8433bffa9e669897243f08edf7845762250e4a)
+---
+ lang/python/setup.py.in | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index e50971c..f4ce64f 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -195,12 +195,6 @@ class BuildExtFirstHack(build):
+         self._generate_gpgme_h(gpgme_h, self._in_build_base("gpgme.h"))
+         self._generate_errors_i(gpg_error_h, self._in_build_base("errors.i"))
+ 
+-        # Keep timestamp to avoid rebuild
+-        for source, target in ((gpgme_h, self._in_build_base("gpgme.h")),
+-                               (gpg_error_h, self._in_build_base("errors.i"))):
+-            if not up_to_date(source, target):
+-                shutil.copystat(source, target)
+-
+         # Copy due to http://bugs.python.org/issue2624
+         # Avoid creating in srcdir
+         for source, target in ((in_srcdir(n), self._in_build_base(n))
diff --git a/debian/patches/0012-python-Read-gpg-error.h-using-the-pre-processor.patch b/debian/patches/0012-python-Read-gpg-error.h-using-the-pre-processor.patch
new file mode 100644
index 0000000..dd1e9f4
--- /dev/null
+++ b/debian/patches/0012-python-Read-gpg-error.h-using-the-pre-processor.patch
@@ -0,0 +1,131 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Sat, 8 Apr 2017 16:34:32 +0300
+Subject: python: Read gpg-error.h using the pre-processor
+
+* lang/python/setup.py.in: Read gpg-error.h using the pre-processor.
+
+--
+
+The libgpg-error may be installed in multilib configuration in which
+there is a wrapper header at /usr/include that includes the actual
+header at /usr/include/*. This causes invalid errors.i generation.
+
+Let the pre-processor extract the header content instead reading it
+explicitly.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 7309ce6f5f7c86570953a141965d4f54cd9ad9a0)
+---
+ lang/python/setup.py.in | 60 ++++++++++++++++++++++++++++---------------------
+ 1 file changed, 35 insertions(+), 25 deletions(-)
+
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index f4ce64f..a1279f8 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -54,13 +54,6 @@ if hasattr(subprocess, "DEVNULL"):
+ else:
+     devnull = open(os.devnull, "w")
+ 
+-try:
+-    subprocess.check_call(gpg_error_config + ['--version'],
+-                          stdout=devnull)
+-except:
+-    sys.exit("Could not find gpg-error-config.  " +
+-             "Please install the libgpg-error development package.")
+-
+ try:
+     subprocess.check_call(gpgme_config + ['--version'],
+                           stdout=devnull)
+@@ -84,13 +77,6 @@ if not (major > 1 or (major == 1 and minor >= 7)):
+ if not gpgme_h:
+     gpgme_h = os.path.join(getconfig("prefix")[0], "include", "gpgme.h")
+ 
+-gpg_error_prefix = getconfig("prefix", config=gpg_error_config)[0]
+-gpg_error_h = os.path.join(gpg_error_prefix, "include", "gpg-error.h")
+-if not os.path.exists(gpg_error_h):
+-    gpg_error_h = \
+-        glob.glob(os.path.join(gpg_error_prefix, "include",
+-                               "*", "gpg-error.h"))[0]
+-
+ define_macros = []
+ libs = getconfig('libs')
+ 
+@@ -150,10 +136,27 @@ def up_to_date(source, target):
+ from distutils.command.build import build
+ class BuildExtFirstHack(build):
+ 
++    def _read_header(self, header, cflags):
++        tmp_include = self._in_build_base("include1.h")
++        with open(tmp_include, 'w') as f:
++            f.write("#include <%s>" % header)
++        return subprocess.check_output(os.environ.get('CPP', 'cc -E').split() + cflags + [tmp_include]).decode('utf-8')
++
++    def _write_if_unchanged(self, target, content):
++        if os.path.exists(target):
++            with open(target) as f:
++                if f.read() == content:
++                    return
++
++        with open(target, "w") as sink:
++            sink.write(content)
++
+     def _generate_gpgme_h(self, source_name, sink_name):
+         if up_to_date(source_name, sink_name):
+             return
+ 
++        print("Using gpgme.h from {}".format(source_name))
++
+         deprec_func = re.compile(r'^(.*typedef.*|.*\(.*\)|[^#]+\s+.+)'
+                                  + r'\s*_GPGME_DEPRECATED(_OUTSIDE_GPGME)?\(.*\);\s*',
+                                  re.S)
+@@ -169,31 +172,38 @@ class BuildExtFirstHack(build):
+                     text = ''
+             sink.write(text)
+ 
+-    def _generate_errors_i(self, source_name, sink_name):
+-        if up_to_date(source_name, sink_name):
+-            return
++    def _generate_errors_i(self):
++
++        try:
++            subprocess.check_call(gpg_error_config + ['--version'],
++                                  stdout=devnull)
++        except:
++            sys.exit("Could not find gpg-error-config.  " +
++                     "Please install the libgpg-error development package.")
++
++        gpg_error_content = self._read_header("gpg-error.h", getconfig("cflags", config=gpg_error_config))
+ 
+         filter_re = re.compile(r'GPG_ERR_[^ ]* =')
+         rewrite_re = re.compile(r' *(.*) = .*')
+ 
+-        with open(sink_name, "w") as sink, open(source_name) as source:
+-            for line in source:
+-                if not filter_re.search(line):
+-                    continue
+-                sink.write(rewrite_re.sub(r'%constant long \1 = \1;'+'\n', line.strip()))
++        errors_i_content = ''
++        for line in gpg_error_content.splitlines():
++            if not filter_re.search(line):
++                continue
++            errors_i_content += rewrite_re.sub(r'%constant long \1 = \1;'+'\n', line.strip())
++
++        self._write_if_unchanged(self._in_build_base("errors.i"), errors_i_content)
+ 
+     def _in_build_base(self, name):
+         return os.path.join(self.build_base, name)
+ 
+     def _generate(self):
+-        print("Building python gpg module using {} and {}.".format(gpgme_h, gpg_error_h))
+-
+         # Cleanup gpgme.h from deprecated functions and typedefs.
+         if not os.path.exists(self.build_base):
+             os.makedirs(self.build_base)
+ 
+         self._generate_gpgme_h(gpgme_h, self._in_build_base("gpgme.h"))
+-        self._generate_errors_i(gpg_error_h, self._in_build_base("errors.i"))
++        self._generate_errors_i()
+ 
+         # Copy due to http://bugs.python.org/issue2624
+         # Avoid creating in srcdir
diff --git a/debian/patches/0013-python-Support-alternatate-libdir-for-tests.patch b/debian/patches/0013-python-Support-alternatate-libdir-for-tests.patch
new file mode 100644
index 0000000..5126902
--- /dev/null
+++ b/debian/patches/0013-python-Support-alternatate-libdir-for-tests.patch
@@ -0,0 +1,63 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Sat, 8 Apr 2017 16:34:33 +0300
+Subject: python: Support alternatate libdir for tests
+
+* lang/python/tests/run-tests.py: Add --python-libdir optional
+parameter.
+
+--
+
+This will make the python tests usable for downstream that build python
+module outside of autotools build system.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit 3cc90b67fa970e716c8672ec5c5f591fa11ab216)
+---
+ lang/python/tests/run-tests.py | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py
+index 5d5294a..a47e3f0 100644
+--- a/lang/python/tests/run-tests.py
++++ b/lang/python/tests/run-tests.py
+@@ -51,6 +51,9 @@ parser.add_argument('--srcdir', type=str,
+ parser.add_argument('--builddir', type=str,
+                     default=os.environ.get("abs_builddir", ""),
+                     help='Location of the tests.')
++parser.add_argument('--python-libdir', type=str,
++                    default=None,
++                    help='Optional location of the in-tree module lib directory.')
+ parser.add_argument('--parallel', action="store_true", default=False,
+                     help='Ignored.  For compatibility with run-tests.scm.')
+ 
+@@ -69,18 +72,20 @@ for interpreter in args.interpreters:
+     version = subprocess.check_output(
+         [interpreter, "-c", "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"]).strip().decode()
+ 
+-    pattern = os.path.join(args.builddir, "..",
+-                           "{0}-gpg".format(os.path.basename(interpreter)),
+-                           "lib*")
+-    builddirs = glob.glob(pattern)
+-    if len(builddirs) == 0:
+-        sys.exit("Build directory matching {0!r} not found.".format(pattern))
+-    elif len(builddirs) > 1:
+-        sys.exit("Multiple build directories matching {0!r} found: {1}".format(
+-            pattern, builddirs))
++    if not args.python_libdir:
++        pattern = os.path.join(args.builddir, "..",
++                               "{0}-gpg".format(os.path.basename(interpreter)),
++                               "lib*")
++        libdirs = glob.glob(pattern)
++        if len(libdirs) == 0:
++            sys.exit("Build directory matching {0!r} not found.".format(pattern))
++        elif len(libdirs) > 1:
++            sys.exit("Multiple build directories matching {0!r} found: {1}".format(
++                pattern, libdirs))
++        python_libdir = libdirs[0]
+ 
+     env = dict(os.environ)
+-    env["PYTHONPATH"] = builddirs[0]
++    env["PYTHONPATH"] = python_libdir
+ 
+     if not args.quiet:
+         print("Running tests using {0} ({1})...".format(interpreter, version))
diff --git a/debian/patches/0014-python-Fix-distcheck.patch b/debian/patches/0014-python-Fix-distcheck.patch
new file mode 100644
index 0000000..99126a4
--- /dev/null
+++ b/debian/patches/0014-python-Fix-distcheck.patch
@@ -0,0 +1,30 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 10 Apr 2017 15:20:34 +0200
+Subject: python: Fix distcheck.
+
+* lang/python/Makefile.am (uninstall-local): Explicitly request the
+scheme 'posix_prefix'.  On Python2.7 the default scheme is
+'posix_local', breaking distcheck.
+
+Fixes-commit: 25e6444b3f4601c7821beab06bc4520deacb007b
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit db476e923415f8e458720aaafde7234b802a33ab)
+---
+ lang/python/Makefile.am | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index 90075f7..8f80a6b 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -93,8 +93,8 @@ install-exec-local:
+ 	done
+ 
+ uninstall-local:
+-	GV=$$(echo $(VERSION) | tr - _); for PYTHON in $(PYTHONS); do \
+-	  PLATLIB="$(prefix)/$$("$${PYTHON}" -c 'import sysconfig, os; print(os.path.relpath(sysconfig.get_path("platlib"), sysconfig.get_config_var("prefix")))')" ; \
++	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 ; \
+ 	done
diff --git a/debian/patches/0015-python-Prune-CLEANFILES.patch b/debian/patches/0015-python-Prune-CLEANFILES.patch
new file mode 100644
index 0000000..2ce030a
--- /dev/null
+++ b/debian/patches/0015-python-Prune-CLEANFILES.patch
@@ -0,0 +1,27 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 10 Apr 2017 15:24:03 +0200
+Subject: python: Prune CLEANFILES.
+
+--
+Fixes-commit: e7d9c0c3d773f826dbd2ed417d04e25c410f3374
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 63bec9f48666d811b65e2ef5cc63f8b731249088)
+---
+ lang/python/Makefile.am | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index 8f80a6b..3fa98b5 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -65,9 +65,7 @@ upload: python$(PYTHON_VERSION)-gpg-dist/gpg-$(VERSION).tar.gz \
+ CLEANFILES = copystamp \
+ 	config.h \
+ 	data.h \
+-	gpg \
+-	files.txt \
+-	install_files.txt
++	gpg
+ 
+ # Remove the rest.
+ #
diff --git a/debian/patches/0016-python-fix-run-tests-missing-python_libdir.patch b/debian/patches/0016-python-fix-run-tests-missing-python_libdir.patch
new file mode 100644
index 0000000..89dea3d
--- /dev/null
+++ b/debian/patches/0016-python-fix-run-tests-missing-python_libdir.patch
@@ -0,0 +1,28 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Tue, 11 Apr 2017 01:55:13 +0300
+Subject: python: fix run-tests missing python_libdir
+
+* lang/python/tests/run-tests.py: Set python_libdir if --python-libdir
+is set.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit d785c053a982bddefd7014dc6856d1af345fe9fb)
+---
+ lang/python/tests/run-tests.py | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py
+index a47e3f0..e2a363e 100644
+--- a/lang/python/tests/run-tests.py
++++ b/lang/python/tests/run-tests.py
+@@ -72,7 +72,9 @@ for interpreter in args.interpreters:
+     version = subprocess.check_output(
+         [interpreter, "-c", "import sys; print('{0}.{1}'.format(sys.version_info[0], sys.version_info[1]))"]).strip().decode()
+ 
+-    if not args.python_libdir:
++    if args.python_libdir:
++        python_libdir = args.python_libdir
++    else:
+         pattern = os.path.join(args.builddir, "..",
+                                "{0}-gpg".format(os.path.basename(interpreter)),
+                                "lib*")
diff --git a/debian/patches/0017-python-use-autoconf-pre-processor-when-building-via-.patch b/debian/patches/0017-python-use-autoconf-pre-processor-when-building-via-.patch
new file mode 100644
index 0000000..826b585
--- /dev/null
+++ b/debian/patches/0017-python-use-autoconf-pre-processor-when-building-via-.patch
@@ -0,0 +1,55 @@
+From: Alon Bar-Lev <alon.barlev at gmail.com>
+Date: Tue, 11 Apr 2017 03:56:00 +0300
+Subject: python: use autoconf pre-processor when building via autoconf
+
+* configure.ac: Add AC_PROG_CPP.
+* lang/python/Makefile.am: Set CPP environment for setup.py to use.
+
+Signed-off-by: Alon Bar-Lev <alon.barlev at gmail.com>
+(cherry picked from commit a827382cafe7f1425455dcc8bf5ef049172eb493)
+---
+ configure.ac            | 1 +
+ lang/python/Makefile.am | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 36c547b..794e0d9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -106,6 +106,7 @@ AH_VERBATIM([_REENTRANT],
+ #endif])
+ 
+ AC_PROG_CC
++AC_PROG_CPP
+ AC_PROG_CXX
+ 
+ # Note: A suitable gitlog-to-changelog script can be found in GnuPG master.
+diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
+index 3fa98b5..8d74cbd 100644
+--- a/lang/python/Makefile.am
++++ b/lang/python/Makefile.am
+@@ -39,6 +39,7 @@ copystamp:
+ 
+ all-local: copystamp
+ 	set -e ; for PYTHON in $(PYTHONS); do \
++	  CPP="$(CPP)" \
+ 	  CFLAGS="$(CFLAGS)" \
+ 	  srcdir="$(srcdir)" \
+ 	  top_builddir="$(top_builddir)" \
+@@ -47,6 +48,7 @@ all-local: copystamp
+ 
+ python$(PYTHON_VERSION)-gpg/dist/gpg-$(VERSION).tar.gz.asc: copystamp
+ 	$(MKDIR_P) python$(PYTHON_VERSION)-gpg-dist
++	CPP="$(CPP)" \
+ 	CFLAGS="$(CFLAGS)" \
+ 	srcdir="$(srcdir)" \
+ 	top_builddir="$(top_builddir)" \
+@@ -80,6 +82,8 @@ clean-local:
+ 
+ install-exec-local:
+ 	set -e ; for PYTHON in $(PYTHONS); do \
++	  CPP="$(CPP)" \
++	  CFLAGS="$(CFLAGS)" \
+ 	  srcdir="$(srcdir)" \
+ 	  top_builddir="$(top_builddir)" \
+ 	  $$PYTHON setup.py \
diff --git a/debian/patches/0018-tests-Update-encrypted-sample-files.patch b/debian/patches/0018-tests-Update-encrypted-sample-files.patch
new file mode 100644
index 0000000..94608de
--- /dev/null
+++ b/debian/patches/0018-tests-Update-encrypted-sample-files.patch
@@ -0,0 +1,80 @@
+From: Justus Winter <justus at g10code.com>
+Date: Mon, 24 Apr 2017 15:29:07 +0200
+Subject: tests: Update encrypted sample files.
+
+* tests/gpg/cipher-1.asc: Update file.
+* tests/gpg/cipher-2.asc: Likewise.
+--
+Convert the plaintext to UTF-8 and re-create the encrypted file.
+
+Fixes-commit: a11450eb048df79a3f2b00ebef6d7cab07ad5054
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit ac28e66f46132ae4a854d04b2f17acd4d55e4296)
+---
+ tests/gpg/cipher-1.asc | 22 ++++++++++------------
+ tests/gpg/cipher-2.asc | 25 ++++++++++++-------------
+ 2 files changed, 22 insertions(+), 25 deletions(-)
+
+diff --git a/tests/gpg/cipher-1.asc b/tests/gpg/cipher-1.asc
+index f0a8ca4..fbb6d58 100644
+--- a/tests/gpg/cipher-1.asc
++++ b/tests/gpg/cipher-1.asc
+@@ -1,15 +1,13 @@
+ -----BEGIN PGP MESSAGE-----
+-Version: GnuPG v1.0.4-2 (GNU/Linux)
+-Comment: For info see http://www.gnupg.org
+ 
+-hQEOA2rm1+5GqHH4EAP/Tcqiuhvrjj+RFBKnWn2A7f1ztV17U2EngYFy8TbZYGNp
+-JoMNdpA7GNZs7iqc/x1epaZDKfaQwWEtARZmK/4nlhB48N+oZeKTm7PXIkRPqrCZ
+-3fxJjCJaU0yrNGuO345DOr0QwDImVhubVEkfgs8yXK2Szx2G8X3LmiaILHAqA2oD
+-/1ZqjY8k+ovrLL/qe8un/NTwzSjKIPVGR6mhLFXmj8fnp2kSsbo+Bhh4MczTRR6l
+-SA32z25vcakKu2qn5Wa4yDcx9NcMt8RHXzmfMDLj6UFq99QqKeLK2ywcIpY9p/GL
+-fQyaf7r3HTVugBSaoOzegLJ+L7MfWohrStkMeLnJQnro0nYBjADVcUQuSS4N3lst
+-Df3XrxxA/iJvxt4F9K27u4tp5U1HDg1CIxVrkMs92LBri3S6ZtfjdoqQ7QghFwGP
+-Kw1lKiWayM6NH9rcCKSgk4kl4P/2l3f78XeFgiywN7UGeSoH3BLMSv9gSxl5KrAz
+-d2imhTMrfEvZ
+-=y4ng
++hQEOA2rm1+5GqHH4EAP/XKz8pdonnZg2dqJhjdas4vQHPxspxLhgf7OuYigodBpI
++l7srTvqtuRsDFNorgURW6DjPqfGqpZsn2uf8enUskunHVMQFBILX38d+G5SkisqF
++uOZUlmh0ZfVocCBGYt8ZPfa9ObmitPmZvhCReCHFlTj588ZjofKuNjmfw+QfmNcD
++/j4z4ijv6dKHQCm7EAjnOsCw9SbrAVpRXjibN7KT+w6QT6m+5w9k4RfhkTOlqrHq
++5d3ZyxLctdTkXlk0hXz1Mey4AEKTtlZGvrQVIhaX4hcB4NFJB0fZJ/pnKypi1H6q
++0bSBq2p6kCzJuNvrEr4wk4B1NsOTBacUSffXLrfsEH2F0ngBzN7d/KHBImu81F8w
++x96f6dELyYetV0UwhyFrPrA3lBQf9q5cNDqPiCHooUFOudQ5t0h7VtSU3fyaYoit
++cJGPFkIxhv+VAbEW/h5muEg3KO1iEqLP4RK3y0Jjy4pyEauAgviM68Vjf4OVvgta
++/IblIrp1FHxoCpA=
++=sEuD
+ -----END PGP MESSAGE-----
+diff --git a/tests/gpg/cipher-2.asc b/tests/gpg/cipher-2.asc
+index 210f3e9..f7c85f3 100644
+--- a/tests/gpg/cipher-2.asc
++++ b/tests/gpg/cipher-2.asc
+@@ -1,16 +1,15 @@
+ -----BEGIN PGP MESSAGE-----
+-Version: GnuPG v1.0.6 (GNU/Linux)
+-Comment: Weitere Infos: siehe http://www.gnupg.org
+ 
+-hQEOA++dwnahcsiBEAP9HgkC1ElQwZRX1X/MBF54Q28dpXKr84IviO4QcbnnhmYk
+-2IlaNe6mr8R7kNM1aqJFK3fnobqnSWwM/VBObMqqYnzZSfclCNsy66sojQJxwXcz
+-DKQKi69BLaC6aTMnX048tOl8pJpR72fkffUOUa5ywDHVVVUClDG3XkIrfM1du3YD
+-/A6vFSrRylupKhQBxdtSUx5IDmpDYwG2vqqbYKoMaQ4pPSKLYV2zskU+pQWRlk6y
+-nwPGY5h9eGz0xYHMPxhe9VnwljeTEDwz5U4CHF3wQ8h5WBxOVx5QN/H/UyjpmoJT
+-ddrIu+8GgajhBVKVYAOqr577exkiSDA60/JrYbKZBvzL0sAJAUu+HoeMPJ+5/RYF
+-pLSdz/3MbVDRJJqzV2TJnEBvFtPa6urzx99P0u4xr+RJMFmR9/99YXhYz7+Y6d/B
+-44F6B3YouYxiK39IoOUcYPZTwb5kaudD5a3mU3XxEhSDUpnyvowPiKQO1T8CPd2u
+-2HsD3KeaOc2VFE0gnvqECvUTQfSCZCk/kil8XVAMHZrEA0bWAYiaHfHEOB8SRCy8
+-rW0wsON4uDXmZpUkfOjFoYZdpJI7fDKkb5uYUzFZDasharEaXb1X/5xSAclx
+-=+eYk
++hQEOA++dwnahcsiBEAQAqaF1yuTJ26FmJHndyaHUjazx7j8/Z/Ht3O+jSAOaoJFR
++84rK4Tte0JQYTCl3XxwSEwr48OAtyeTstLjabGAvBoHrXVP3xC0U7kBalZm2lwcq
++A8dDDoa3uMkWi1OJ3e2o79/z6SdTHEgRIRomAku1JaXFGTd8OsFhW782RpKUBOID
++/jMs9o2sa/gDhWVaeC3SaQovl2xb45ev0nMibED916BQvv3NkH5/EzeM6v788h63
++4yUkWWNr0/bnJ21chlxIbvICjHfuGAEDw+i4HhK/nLBL3Ep4ADtLP7OPZJHlcQgI
++g8mAztasBxTGGUuFYvRT0X7sbaSPxLR26vbTCYAo/P/80sA4AYGhBuYPsRN4JzX9
++QaSrToKjPbaZqq+nHQYCvi6m5xAjMT0HVdXejMtZMKwv4TRm7IVCimtIZqrlvw7c
++Kj+ZcDGq9qb7urnzC5mdAZkXyNtZxmMKYFI0ci7zMnflvIM87JrVEjZbjjiXlcVy
++mSxhufOOweLJARkJ4mKVq1tr8REu8/ots4fDzUIAITM3z8pKA7doWAH2VTo0Idmc
++wYOoTLkiq1Z8fxeryB6U66C831PDiWe7W0usRSVo5rZ7laLZeOGl33fAAZCNLTgv
++tOPWWg5rCpRTVXgQ6Edl7DtzKI1z4EJbuEUs6shW+OT3bNISiDz2am8remU=
++=9AEU
+ -----END PGP MESSAGE-----
diff --git a/debian/patches/0019-doc-Improve-doc-on-passphrase_cb-pinentry-mode.patch b/debian/patches/0019-doc-Improve-doc-on-passphrase_cb-pinentry-mode.patch
new file mode 100644
index 0000000..9ca850a
--- /dev/null
+++ b/debian/patches/0019-doc-Improve-doc-on-passphrase_cb-pinentry-mode.patch
@@ -0,0 +1,45 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Mon, 24 Apr 2017 16:46:09 +0200
+Subject: doc: Improve doc on passphrase_cb / pinentry mode
+
+* doc/gpgme.texi (Passphrase Callback): Mention pinentry_mode and
+restrictions.
+(Pinentry Mode): Fix wording and clarify versions that need
+loopback mode for passphrase_cb to work.
+
+(cherry picked from commit 8d61aba1fe0379ba14494f8ae2011ba531554ef4)
+---
+ doc/gpgme.texi | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/doc/gpgme.texi b/doc/gpgme.texi
+index 40423cf..bc40430 100644
+--- a/doc/gpgme.texi
++++ b/doc/gpgme.texi
+@@ -2597,11 +2597,11 @@ Return a Pinentry error @code{No Pinentry}.
+ 
+ @item GPGME_PINENTRY_MODE_LOOPBACK
+ Redirect Pinentry queries to the caller.
+-This enables the use of @code{gpgme_set_passphrase_cb} whis pinentry
+-queries redirected to gpgme.
++This enables the use of @code{gpgme_set_passphrase_cb} because pinentry
++queries are redirected to gpgme.
+ 
+-Note: This mode requires @code{allow-loopback-pinentry} to be enabled
+-in the @file{gpg-agent.conf} or an agent started with that option.
++Note: For 2.1.0 - 2.1.12 this mode requires @code{allow-loopback-pinentry}
++to be enabled in the @file{gpg-agent.conf} or an agent started with that option.
+ 
+ @end table
+ @end deftp
+@@ -2763,6 +2763,10 @@ character before returning from the callback.
+ If an error occurs, return the corresponding @code{gpgme_error_t}
+ value.  You can use the error code @code{GPG_ERR_CANCELED} to abort
+ the operation.  Otherwise, return @code{0}.
++
++Note: The passphrase_cb only works with GnuPG 1.x and 2.1.x and not
++with the 2.0.x series. See @code{gpgme_set_pinentry_mode} for more
++details on 2.1.x usage.
+ @end deftp
+ 
+ @deftypefun void gpgme_set_passphrase_cb (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_passphrase_cb_t @var{passfunc}}, @w{void *@var{hook_value}})
diff --git a/debian/patches/0020-core-Don-t-split-gpgconf-strings-on-comma.patch b/debian/patches/0020-core-Don-t-split-gpgconf-strings-on-comma.patch
new file mode 100644
index 0000000..14eae07
--- /dev/null
+++ b/debian/patches/0020-core-Don-t-split-gpgconf-strings-on-comma.patch
@@ -0,0 +1,40 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Wed, 5 Apr 2017 18:23:48 +0200
+Subject: core: Don't split gpgconf strings on comma
+
+* src/engine-gpgconf.c (gpgconf_parse_option): Don't split
+strings on comma.
+
+--
+This only affects values where the main type is string. Values
+with the alt_type string but another main type are still split
+to keep lists (e.g. groups) working.
+
+(cherry picked from commit df4eb611e33dcab7bebf07b13734c7db7ccf40da)
+---
+ src/engine-gpgconf.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c
+index 6f7c8ac..af5f110 100644
+--- a/src/engine-gpgconf.c
++++ b/src/engine-gpgconf.c
+@@ -399,7 +399,7 @@ gpgconf_parse_option (gpgme_conf_opt_t opt,
+ 		      gpgme_conf_arg_t *arg_p, char *line)
+ {
+   gpgme_error_t err;
+-  char *mark;
++  char *mark = NULL;
+ 
+   if (!line[0])
+     return 0;
+@@ -408,7 +408,8 @@ gpgconf_parse_option (gpgme_conf_opt_t opt,
+     {
+       gpgme_conf_arg_t arg;
+ 
+-      mark = strchr (line, ',');
++      if (opt->type != GPGME_CONF_STRING)
++        mark = strchr (line, ',');
+       if (mark)
+ 	*mark = '\0';
+ 
diff --git a/debian/patches/0021-qt-tests-Don-t-use-internal-API.patch b/debian/patches/0021-qt-tests-Don-t-use-internal-API.patch
new file mode 100644
index 0000000..0ff21ad
--- /dev/null
+++ b/debian/patches/0021-qt-tests-Don-t-use-internal-API.patch
@@ -0,0 +1,153 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Wed, 10 May 2017 10:18:41 +0200
+Subject: qt, tests: Don't use internal API
+
+* lang/qt/tests/t-encrypt.cpp, lang/qt/tests/t-tofuinfo.cpp:
+Only use exported API.
+
+--
+With the Job::Context hack we no longer need to use internal API.
+
+(cherry picked from commit b56f398eff4e3e70dea714c3174a5512dd9bcf33)
+---
+ lang/qt/tests/t-encrypt.cpp  | 29 +++++++++++++++--------------
+ lang/qt/tests/t-tofuinfo.cpp |  7 ++++---
+ 2 files changed, 19 insertions(+), 17 deletions(-)
+
+diff --git a/lang/qt/tests/t-encrypt.cpp b/lang/qt/tests/t-encrypt.cpp
+index a2d8dc4..d9b5a5c 100644
+--- a/lang/qt/tests/t-encrypt.cpp
++++ b/lang/qt/tests/t-encrypt.cpp
+@@ -41,10 +41,10 @@
+ #include "encryptjob.h"
+ #include "signencryptjob.h"
+ #include "signingresult.h"
+-#include "qgpgmeencryptjob.h"
++#include "encryptjob.h"
+ #include "encryptionresult.h"
+ #include "decryptionresult.h"
+-#include "qgpgmedecryptjob.h"
++#include "decryptjob.h"
+ #include "qgpgmebackend.h"
+ #include "keylistresult.h"
+ #include "engineinfo.h"
+@@ -105,11 +105,11 @@ private Q_SLOTS:
+         if (!decryptSupported()) {
+             return;
+         }
+-        auto ctx = Context::createForProtocol(OpenPGP);
++        auto decJob = openpgp()->decryptJob();
++        auto ctx = Job::context(decJob);
+         TestPassphraseProvider provider;
+         ctx->setPassphraseProvider(&provider);
+         ctx->setPinentryMode(Context::PinentryLoopback);
+-        auto decJob = new QGpgMEDecryptJob(ctx);
+         QByteArray plainText;
+         auto decResult = decJob->exec(cipherText, plainText);
+         QVERIFY(!decResult.error());
+@@ -176,13 +176,13 @@ private Q_SLOTS:
+         if (!decryptSupported()) {
+             return;
+         }
+-        auto ctx = Context::createForProtocol(OpenPGP);
++        auto job = openpgp()->encryptJob();
++        auto ctx = Job::context(job);
+         TestPassphraseProvider provider;
+         ctx->setPassphraseProvider(&provider);
+         ctx->setPinentryMode(Context::PinentryLoopback);
+         ctx->setArmor(true);
+         ctx->setTextMode(true);
+-        auto job = new QGpgMEEncryptJob(ctx);
+         QByteArray cipherText;
+         auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
+         delete job;
+@@ -192,10 +192,10 @@ private Q_SLOTS:
+ 
+         killAgent(mDir.path());
+ 
+-        auto ctx2 = Context::createForProtocol(OpenPGP);
++        auto decJob = openpgp()->decryptJob();
++        auto ctx2 = Job::context(decJob);
+         ctx2->setPassphraseProvider(&provider);
+         ctx2->setPinentryMode(Context::PinentryLoopback);
+-        auto decJob = new QGpgMEDecryptJob(ctx2);
+         QByteArray plainText;
+         auto decResult = decJob->exec(cipherText, plainText);
+         QVERIFY(!result.error());
+@@ -239,13 +239,14 @@ private:
+         if (!decryptSupported()) {
+             return;
+         }
+-        auto ctx = Context::createForProtocol(OpenPGP);
++
++        auto decJob = openpgp()->decryptJob();
++        auto ctx = Job::context(decJob);
+         TestPassphraseProvider provider;
+         ctx->setPassphraseProvider(&provider);
+         ctx->setPinentryMode(Context::PinentryLoopback);
+         ctx->setDecryptionFlags(Context::DecryptUnwrap);
+ 
+-        auto decJob = new QGpgMEDecryptJob(ctx);
+         QByteArray plainText;
+         auto decResult = decJob->exec(cipherText, plainText);
+ 
+@@ -283,12 +284,12 @@ private:
+         QVERIFY(keys.size() == 1);
+         delete listjob;
+ 
+-        auto ctx = Context::createForProtocol(OpenPGP);
++        auto job = openpgp()->encryptJob();
++        auto ctx = Job::context(job);
+         ctx->setPassphraseProvider(new TestPassphraseProvider);
+         ctx->setPinentryMode(Context::PinentryLoopback);
+         ctx->setArmor(true);
+         ctx->setTextMode(true);
+-        auto job = new QGpgMEEncryptJob(ctx);
+         QByteArray cipherText;
+         printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
+         auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
+@@ -311,11 +312,11 @@ private:
+         agentConf.write("allow-loopback-pinentry");
+         agentConf.close();
+ 
+-        auto ctx2 = Context::createForProtocol(OpenPGP);
++        auto decJob = openpgp()->decryptJob();
++        auto ctx2 = Job::context(decJob);
+         ctx2->setPassphraseProvider(new TestPassphraseProvider);
+         ctx2->setPinentryMode(Context::PinentryLoopback);
+         ctx2->setTextMode(true);
+-        auto decJob = new QGpgMEDecryptJob(ctx2);
+         QByteArray plainText;
+         auto decResult = decJob->exec(cipherText, plainText);
+         QVERIFY(!decResult.error());
+diff --git a/lang/qt/tests/t-tofuinfo.cpp b/lang/qt/tests/t-tofuinfo.cpp
+index e16b1fd..2dd25ea 100644
+--- a/lang/qt/tests/t-tofuinfo.cpp
++++ b/lang/qt/tests/t-tofuinfo.cpp
+@@ -47,10 +47,11 @@
+ #include "importresult.h"
+ #include "keylistjob.h"
+ #include "keylistresult.h"
+-#include "qgpgmesignjob.h"
++#include "signjob.h"
+ #include "key.h"
+ #include "t-support.h"
+ #include "engineinfo.h"
++#include "context.h"
+ #include <iostream>
+ 
+ using namespace QGpgME;
+@@ -133,11 +134,11 @@ private:
+ 
+     void signAndVerify(const QString &what, const GpgME::Key &key, int expected)
+     {
+-        Context *ctx = Context::createForProtocol(OpenPGP);
++        auto job = openpgp()->signJob();
++        auto ctx = Job::context(job);
+         TestPassphraseProvider provider;
+         ctx->setPassphraseProvider(&provider);
+         ctx->setPinentryMode(Context::PinentryLoopback);
+-        auto *job = new QGpgMESignJob(ctx);
+ 
+         std::vector<Key> keys;
+         keys.push_back(key);
diff --git a/debian/patches/0022-qt-Undeprecate-API-that-I-find-useful.patch b/debian/patches/0022-qt-Undeprecate-API-that-I-find-useful.patch
new file mode 100644
index 0000000..f17de30
--- /dev/null
+++ b/debian/patches/0022-qt-Undeprecate-API-that-I-find-useful.patch
@@ -0,0 +1,92 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Wed, 10 May 2017 10:22:23 +0200
+Subject: qt: Undeprecate API that I find useful
+
+* lang/qt/src/decryptjob.h,
+lang/qt/src/decryptverifyjob.h,
+lang/qt/src/signencryptjob.h,
+lang/qt/src/verifydetachedjob.h,
+lang/qt/src/verifyopaquejob.h: Undeprecate ByteArray based API.
+
+--
+While an IODevice may be more performant the ByteArray API is
+a very easy way to get started with QGpgME as it allows you
+basically to encrypt / decrypt any QString.
+
+This also fixes a ton of deprecation warnings in KDE where this
+API is used all over the place.
+
+(cherry picked from commit cc2ef3d07c0d261bb9e8e8c0f2706e1a08e4ec53)
+---
+ lang/qt/src/decryptjob.h        | 2 +-
+ lang/qt/src/decryptverifyjob.h  | 2 +-
+ lang/qt/src/signencryptjob.h    | 2 +-
+ lang/qt/src/verifydetachedjob.h | 2 +-
+ lang/qt/src/verifyopaquejob.h   | 2 +-
+ 5 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/lang/qt/src/decryptjob.h b/lang/qt/src/decryptjob.h
+index c4fc86f..f59d753 100644
+--- a/lang/qt/src/decryptjob.h
++++ b/lang/qt/src/decryptjob.h
+@@ -75,7 +75,7 @@ public:
+        Starts the decryption operation. \a cipherText is the data to
+        decrypt.
+     */
+-    virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &cipherText) = 0;
++    virtual GpgME::Error start(const QByteArray &cipherText) = 0;
+ 
+     /*!
+       \overload
+diff --git a/lang/qt/src/decryptverifyjob.h b/lang/qt/src/decryptverifyjob.h
+index 97af008..f64d747 100644
+--- a/lang/qt/src/decryptverifyjob.h
++++ b/lang/qt/src/decryptverifyjob.h
+@@ -76,7 +76,7 @@ public:
+        Starts the combined decryption and verification operation.
+        \a cipherText is the data to decrypt and later verify.
+     */
+-    virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &cipherText) = 0;
++    virtual GpgME::Error start(const QByteArray &cipherText) = 0;
+ 
+     /*!
+       \overload
+diff --git a/lang/qt/src/signencryptjob.h b/lang/qt/src/signencryptjob.h
+index 4e07744..427912d 100644
+--- a/lang/qt/src/signencryptjob.h
++++ b/lang/qt/src/signencryptjob.h
+@@ -94,7 +94,7 @@ public:
+        \em recipient keys will not be performed, but full validity
+        assumed for all \em recipient keys without further checks.
+     */
+-    virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const std::vector<GpgME::Key> &signers,
++    virtual GpgME::Error start(const std::vector<GpgME::Key> &signers,
+             const std::vector<GpgME::Key> &recipients,
+             const QByteArray &plainText,
+             bool alwaysTrust = false) = 0;
+diff --git a/lang/qt/src/verifydetachedjob.h b/lang/qt/src/verifydetachedjob.h
+index b339a8c..792fec8 100644
+--- a/lang/qt/src/verifydetachedjob.h
++++ b/lang/qt/src/verifydetachedjob.h
+@@ -77,7 +77,7 @@ public:
+        signature data, while \a signedData contains the data over
+        which the signature was made.
+     */
+-    virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &signature,
++    virtual GpgME::Error start(const QByteArray &signature,
+             const QByteArray &signedData) = 0;
+ 
+     /*!
+diff --git a/lang/qt/src/verifyopaquejob.h b/lang/qt/src/verifyopaquejob.h
+index f064049..4d62576 100644
+--- a/lang/qt/src/verifyopaquejob.h
++++ b/lang/qt/src/verifyopaquejob.h
+@@ -76,7 +76,7 @@ public:
+        signature data, while \a signedData contains the data over
+        which the signature was made.
+     */
+-    virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &signedData) = 0;
++    virtual GpgME::Error start(const QByteArray &signedData) = 0;
+ 
+     /*!
+       \overload
diff --git a/debian/patches/0023-qt-Add-a-missing-include-functional.patch b/debian/patches/0023-qt-Add-a-missing-include-functional.patch
new file mode 100644
index 0000000..2699363
--- /dev/null
+++ b/debian/patches/0023-qt-Add-a-missing-include-functional.patch
@@ -0,0 +1,33 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Wed, 10 May 2017 10:24:18 +0200
+Subject: qt: Add a missing include <functional>
+MIME-Version: 1.0
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+* lang/qt/src/qgpgmenewcryptoconfig.cpp: Include functional.
+
+--
+This is intended to fix compilation against the c++ stdlib from
+Gentoo / GCC 7.
+
+Patch provided by Martin Väth.
+GnuPG-Bug-Id: T3151
+
+(cherry picked from commit 5e27bf98b4c48cf6a239bcc94b7b67515ff339e7)
+---
+ lang/qt/src/qgpgmenewcryptoconfig.cpp | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lang/qt/src/qgpgmenewcryptoconfig.cpp b/lang/qt/src/qgpgmenewcryptoconfig.cpp
+index 6901eef..87d2d38 100644
+--- a/lang/qt/src/qgpgmenewcryptoconfig.cpp
++++ b/lang/qt/src/qgpgmenewcryptoconfig.cpp
+@@ -48,6 +48,7 @@
+ 
+ #include <sstream>
+ #include <string>
++#include <functional>
+ #include <cassert>
+ #include <functional>
+ 
diff --git a/debian/patches/0024-qt-Stop-agent-on-clean.patch b/debian/patches/0024-qt-Stop-agent-on-clean.patch
new file mode 100644
index 0000000..3982c25
--- /dev/null
+++ b/debian/patches/0024-qt-Stop-agent-on-clean.patch
@@ -0,0 +1,24 @@
+From: Justus Winter <justus at g10code.com>
+Date: Wed, 10 May 2017 15:23:56 +0200
+Subject: qt: Stop agent on clean.
+
+* lang/qt/tests/Makefile.am (clean-local): Stop agent.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 093b5497b7231590ce91ccf73ba64ebc0757f9e9)
+---
+ lang/qt/tests/Makefile.am | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
+index fb45eec..fbcb63e 100644
+--- a/lang/qt/tests/Makefile.am
++++ b/lang/qt/tests/Makefile.am
+@@ -69,6 +69,7 @@ CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
+ 	gpg.conf tofu.db
+ 
+ clean-local:
++	-$(top_srcdir)/tests/start-stop-agent --stop
+ 	-rm -fR  private-keys-v1.d crls.d
+ 
+ export GNUPGHOME := $(abs_builddir)
diff --git a/debian/patches/0025-tests-Harmonize-test-suites.patch b/debian/patches/0025-tests-Harmonize-test-suites.patch
new file mode 100644
index 0000000..cb5cbad
--- /dev/null
+++ b/debian/patches/0025-tests-Harmonize-test-suites.patch
@@ -0,0 +1,93 @@
+From: Justus Winter <justus at g10code.com>
+Date: Wed, 10 May 2017 15:49:54 +0200
+Subject: tests: Harmonize test suites.
+
+* lang/python/tests/Makefile.am: Create test environment as part of
+'make all'.
+* tests/gpg/Makefile.am: Make sure the private keystore is created
+first.
+* tests/gpgsm/Makefile.am: Create test environment as part of
+'make all'.  Make sure the private keystore is created
+first.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 15adff073bb89dc032d8342cfbbdad2850943f52)
+---
+ lang/python/tests/Makefile.am |  5 ++++-
+ tests/gpg/Makefile.am         |  2 +-
+ tests/gpgsm/Makefile.am       | 11 ++++++++---
+ 3 files changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am
+index 9c19a13..b62b524 100644
+--- a/lang/python/tests/Makefile.am
++++ b/lang/python/tests/Makefile.am
+@@ -71,7 +71,7 @@ check: xcheck
+ 
+ .PHONY: xcheck
+ 
+-xcheck: ./pubring-stamp
++xcheck:
+ 	$(TESTS_ENVIRONMENT) $(PYTHON) $(srcdir)/run-tests.py \
+ 	  --interpreters="$(PYTHONS)" --srcdir=$(srcdir) $(TESTFLAGS) \
+ 	  $(XTESTS)
+@@ -93,6 +93,9 @@ clean-local:
+ 	-rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol
+ 
+ 
++BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
++           private-keys-v1.d/gpg-sample.stamp
++
+ ./private-keys-v1.d/gpg-sample.stamp: $(private_keys)
+ 	$(MKDIR_P) ./private-keys-v1.d
+ 	for k in $(private_keys); do \
+diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
+index 4cba303..2ac032b 100644
+--- a/tests/gpg/Makefile.am
++++ b/tests/gpg/Makefile.am
+@@ -95,7 +95,7 @@ export GPG_AGENT_INFO :=
+         done
+ 	echo x > ./private-keys-v1.d/gpg-sample.stamp
+ 
+-./pubring-stamp: $(srcdir)/pubdemo.asc
++./pubring-stamp: $(srcdir)/pubdemo.asc ./private-keys-v1.d/gpg-sample.stamp
+ 	$(GPG) --batch --no-permission-warning \
+                --import $(srcdir)/pubdemo.asc
+ 	-$(GPG) --batch --no-permission-warning \
+diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
+index 46d6a9b..76e4938 100644
+--- a/tests/gpgsm/Makefile.am
++++ b/tests/gpgsm/Makefile.am
+@@ -44,7 +44,7 @@ noinst_PROGRAMS = $(c_tests) t-genkey cms-keylist cms-decrypt
+ 
+ key_id = 32100C27173EF6E9C4E9A25D3D69F86D37A4F939
+ 
+-CLEANFILES = pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \
++CLEANFILES = pubring-stamp pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \
+ 	random_seed S.gpg-agent
+ 
+ clean-local:
+@@ -62,16 +62,21 @@ export GNUPGHOME := $(abs_builddir)
+ 
+ export GPG_AGENT_INFO :=
+ 
+-./pubring.kbx: $(srcdir)/cert_g10code_test1.der
++BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
++           private-keys-v1.d/gpg-sample.stamp
++
++./pubring-stamp: $(srcdir)/cert_g10code_test1.der ./private-keys-v1.d/gpg-sample.stamp
+ 	$(GPGSM) --import $(srcdir)/cert_g10code_test1.der
++	touch pubring-stamp
+ 
+ ./gpgsm.conf:
+ 	echo disable-crl-checks > ./gpgsm.conf
+ 	echo faked-system-time 1008241200 >> ./gpgsm.conf
+ 
+-./private-keys-v1.d/$(key_id).key: $(srcdir)/$(key_id)
++./private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
+ 	$(MKDIR_P) ./private-keys-v1.d
+ 	cp $(srcdir)/$(key_id) private-keys-v1.d/$(key_id).key
++	echo x > ./private-keys-v1.d/gpg-sample.stamp
+ 
+ ./trustlist.txt:
+ 	echo $(key_id) > ./trustlist.txt
diff --git a/debian/patches/0026-tests-Make-sure-to-kill-all-previously-running-daemo.patch b/debian/patches/0026-tests-Make-sure-to-kill-all-previously-running-daemo.patch
new file mode 100644
index 0000000..206fd7a
--- /dev/null
+++ b/debian/patches/0026-tests-Make-sure-to-kill-all-previously-running-daemo.patch
@@ -0,0 +1,73 @@
+From: Justus Winter <justus at g10code.com>
+Date: Wed, 10 May 2017 15:52:12 +0200
+Subject: tests: Make sure to kill all previously running daemons.
+
+* lang/python/tests/Makefile.am: Kill all previously running daemons
+before creating the private key store.
+* lang/qt/tests/Makefile.am: Likewise.
+* tests/gpg/Makefile.am: Likewise.
+* tests/gpgsm/Makefile.am: Likewise.
+--
+
+Now that the daemons sockets are no longer created in the GNUPGHOME,
+we cannot rely on cleaning the build directory to make sure they are
+shut down.  Therefore, we explicitly kill any running daemons when
+creating the test environment.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit a226eca84670ef4e171c3a54e7caefb3a89254a4)
+---
+ lang/python/tests/Makefile.am | 1 +
+ lang/qt/tests/Makefile.am     | 1 +
+ tests/gpg/Makefile.am         | 1 +
+ tests/gpgsm/Makefile.am       | 1 +
+ 4 files changed, 4 insertions(+)
+
+diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am
+index b62b524..790d8f8 100644
+--- a/lang/python/tests/Makefile.am
++++ b/lang/python/tests/Makefile.am
+@@ -97,6 +97,7 @@ BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
+            private-keys-v1.d/gpg-sample.stamp
+ 
+ ./private-keys-v1.d/gpg-sample.stamp: $(private_keys)
++	-gpgconf --kill all
+ 	$(MKDIR_P) ./private-keys-v1.d
+ 	for k in $(private_keys); do \
+           cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \
+diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
+index fbcb63e..6f3936b 100644
+--- a/lang/qt/tests/Makefile.am
++++ b/lang/qt/tests/Makefile.am
+@@ -76,6 +76,7 @@ export GNUPGHOME := $(abs_builddir)
+ 
+ pubring-stamp: $(top_srcdir)/tests/gpg/pubdemo.asc \
+ 	             $(top_srcdir)/tests/gpg/secdemo.asc
++	-gpgconf --kill all
+ 	echo "ignore-invalid-option allow-loopback-pinentry" > $(abs_builddir)/gpg-agent.conf
+ 	echo "allow-loopback-pinentry" >> gpg-agent.conf
+ 	echo "ignore-invalid-option pinentry-mode" > gpg.conf
+diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
+index 2ac032b..ba23aff 100644
+--- a/tests/gpg/Makefile.am
++++ b/tests/gpg/Makefile.am
+@@ -89,6 +89,7 @@ export GNUPGHOME := $(abs_builddir)
+ export GPG_AGENT_INFO :=
+ 
+ ./private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(private_keys)
++	-gpgconf --kill all
+ 	$(MKDIR_P) ./private-keys-v1.d
+ 	for k in $(private_keys); do \
+           cp $(srcdir)/$$k private-keys-v1.d/$$k.key; \
+diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
+index 76e4938..adae6a2 100644
+--- a/tests/gpgsm/Makefile.am
++++ b/tests/gpgsm/Makefile.am
+@@ -74,6 +74,7 @@ BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
+ 	echo faked-system-time 1008241200 >> ./gpgsm.conf
+ 
+ ./private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
++	-gpgconf --kill all
+ 	$(MKDIR_P) ./private-keys-v1.d
+ 	cp $(srcdir)/$(key_id) private-keys-v1.d/$(key_id).key
+ 	echo x > ./private-keys-v1.d/gpg-sample.stamp
diff --git a/debian/patches/0027-python-Fix-test-environment-creation.patch b/debian/patches/0027-python-Fix-test-environment-creation.patch
new file mode 100644
index 0000000..1276861
--- /dev/null
+++ b/debian/patches/0027-python-Fix-test-environment-creation.patch
@@ -0,0 +1,25 @@
+From: Justus Winter <justus at g10code.com>
+Date: Wed, 10 May 2017 16:19:52 +0200
+Subject: python: Fix test environment creation.
+
+* lang/python/tests/Makefile.am (pubring-stamp): Do not depend on the
+configuration files, this can trigger superfluous rebuilds.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 6b4dd3b929ac23271bfa96edb9dbb142eca0a30f)
+---
+ lang/python/tests/Makefile.am | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am
+index 790d8f8..d0dde1d 100644
+--- a/lang/python/tests/Makefile.am
++++ b/lang/python/tests/Makefile.am
+@@ -105,7 +105,6 @@ BUILT_SOURCES = gpg.conf gpg-agent.conf pubring-stamp \
+ 	echo x > ./private-keys-v1.d/gpg-sample.stamp
+ 
+ ./pubring-stamp: $(test_srcdir)/pubdemo.asc           \
+-                 ./gpg.conf ./gpg-agent.conf          \
+                  ./private-keys-v1.d/gpg-sample.stamp
+ 	$(GPG) --batch --no-permission-warning \
+                --import $(test_srcdir)/pubdemo.asc
diff --git a/debian/patches/0028-tests-Remove-remnants-of-check-local.patch b/debian/patches/0028-tests-Remove-remnants-of-check-local.patch
new file mode 100644
index 0000000..6ccf789
--- /dev/null
+++ b/debian/patches/0028-tests-Remove-remnants-of-check-local.patch
@@ -0,0 +1,35 @@
+From: Justus Winter <justus at g10code.com>
+Date: Wed, 10 May 2017 16:31:58 +0200
+Subject: tests: Remove remnants of 'check-local'.
+
+* tests/gpgsm/Makefile.am (check-local): Drop rule and the dependency
+on it.
+--
+Previously, the test environment was created during 'make check'.
+Nowadays we create it using 'BUILT_SOURCES' during 'make all'.  Drop
+remnant of the previous method.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit a9b4c0ad0d1085ff76742e44cf0cf926e89d1f4c)
+---
+ tests/gpgsm/Makefile.am | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
+index adae6a2..c73faea 100644
+--- a/tests/gpgsm/Makefile.am
++++ b/tests/gpgsm/Makefile.am
+@@ -51,13 +51,6 @@ clean-local:
+ 	-$(top_srcdir)/tests/start-stop-agent --stop
+ 	-rm -fR private-keys-v1.d
+ 
+-check-local: ./pubring.kbx ./gpgsm.conf \
+-             ./private-keys-v1.d/$(key_id).key ./trustlist.txt
+-
+-# To guarantee that check-local is run before any tests we add this
+-# dependency:
+-initial.test : check-local
+-
+ export GNUPGHOME := $(abs_builddir)
+ 
+ export GPG_AGENT_INFO :=
diff --git a/debian/patches/0029-python-Fix-build-in-certain-cases.patch b/debian/patches/0029-python-Fix-build-in-certain-cases.patch
new file mode 100644
index 0000000..fb6b68f
--- /dev/null
+++ b/debian/patches/0029-python-Fix-build-in-certain-cases.patch
@@ -0,0 +1,30 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 18 May 2017 11:42:13 +0200
+Subject: python: Fix build in certain cases.
+
+* lang/python/setup.py.in: Prepend the Python build dir to the list of
+include directories so that it takes precedence over any other include
+directory.
+--
+Fixes the build in case an older 'gpgme.h' is installed and is picked
+up by the compiler when compiling the Python module.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 84a203e60b9935bd8536cd2832fbc55d7f011341)
+---
+ lang/python/setup.py.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lang/python/setup.py.in b/lang/python/setup.py.in
+index a1279f8..f9dda20 100755
+--- a/lang/python/setup.py.in
++++ b/lang/python/setup.py.in
+@@ -223,7 +223,7 @@ class BuildExtFirstHack(build):
+         swig_sources.extend((self._in_build_base('gpgme.i'), self._in_build_base('helpers.c')))
+         swig_opts.extend(['-I' + self.build_base,
+                           '-outdir', os.path.join(self.build_lib, 'gpg')])
+-        include_dirs.append(self.build_base)
++        include_dirs.insert(0, self.build_base)
+ 
+         self.run_command('build_ext')
+         build.run(self)
diff --git a/debian/patches/0030-core-Sort-the-status-table.patch b/debian/patches/0030-core-Sort-the-status-table.patch
new file mode 100644
index 0000000..0e0bf8f
--- /dev/null
+++ b/debian/patches/0030-core-Sort-the-status-table.patch
@@ -0,0 +1,85 @@
+From: Justus Winter <justus at g10code.com>
+Date: Tue, 30 May 2017 12:09:23 +0200
+Subject: core: Sort the status table.
+
+--
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 92574406fb5fd456bc5bf85c7d906f06c4680632)
+---
+ src/status-table.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/src/status-table.c b/src/status-table.c
+index c9bf357..6451134 100644
+--- a/src/status-table.c
++++ b/src/status-table.c
+@@ -43,10 +43,10 @@ static struct status_table_s status_table[] =
+   { "ALREADY_SIGNED", GPGME_STATUS_ALREADY_SIGNED },
+   { "ATTRIBUTE",         GPGME_STATUS_ATTRIBUTE        },
+   { "BACKUP_KEY_CREATED", GPGME_STATUS_BACKUP_KEY_CREATED },
+-  { "BAD_PASSPHRASE", GPGME_STATUS_BAD_PASSPHRASE },
+   { "BADARMOR", GPGME_STATUS_BADARMOR },
+   { "BADMDC", GPGME_STATUS_BADMDC },
+   { "BADSIG", GPGME_STATUS_BADSIG },
++  { "BAD_PASSPHRASE", GPGME_STATUS_BAD_PASSPHRASE },
+   { "BEGIN_DECRYPTION", GPGME_STATUS_BEGIN_DECRYPTION },
+   { "BEGIN_ENCRYPTION", GPGME_STATUS_BEGIN_ENCRYPTION },
+   { "BEGIN_SIGNING",     GPGME_STATUS_BEGIN_SIGNING    },
+@@ -73,22 +73,22 @@ static struct status_table_s status_table[] =
+   { "GET_BOOL", GPGME_STATUS_GET_BOOL },
+   { "GET_HIDDEN", GPGME_STATUS_GET_HIDDEN },
+   { "GET_LINE", GPGME_STATUS_GET_LINE },
+-  { "GOOD_PASSPHRASE", GPGME_STATUS_GOOD_PASSPHRASE },
+   { "GOODMDC", GPGME_STATUS_GOODMDC },
+   { "GOODSIG", GPGME_STATUS_GOODSIG },
++  { "GOOD_PASSPHRASE", GPGME_STATUS_GOOD_PASSPHRASE },
+   { "GOT_IT", GPGME_STATUS_GOT_IT },
++  { "IMPORTED", GPGME_STATUS_IMPORTED },
+   { "IMPORT_OK", GPGME_STATUS_IMPORT_OK },
+   { "IMPORT_PROBLEM", GPGME_STATUS_IMPORT_PROBLEM },
+   { "IMPORT_RES", GPGME_STATUS_IMPORT_RES },
+-  { "IMPORTED", GPGME_STATUS_IMPORTED },
+   { "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN },
+   { "INV_RECP", GPGME_STATUS_INV_RECP },
+   { "INV_SGNR", GPGME_STATUS_INV_SGNR },
++  { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED },
++  { "KEYREVOKED", GPGME_STATUS_KEYREVOKED },
+   { "KEY_CONSIDERED", GPGME_STATUS_KEY_CONSIDERED },
+   { "KEY_CREATED", GPGME_STATUS_KEY_CREATED },
+   { "KEY_NOT_CREATED",   GPGME_STATUS_KEY_NOT_CREATED  },
+-  { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED },
+-  { "KEYREVOKED", GPGME_STATUS_KEYREVOKED },
+   { "LEAVE", GPGME_STATUS_LEAVE },
+   { "MISSING_PASSPHRASE", GPGME_STATUS_MISSING_PASSPHRASE },
+   { "MOUNTPOINT",        GPGME_STATUS_MOUNTPOINT       },
+@@ -96,14 +96,14 @@ static struct status_table_s status_table[] =
+   { "NEED_PASSPHRASE_PIN", GPGME_STATUS_NEED_PASSPHRASE_PIN },
+   { "NEED_PASSPHRASE_SYM", GPGME_STATUS_NEED_PASSPHRASE_SYM },
+   { "NEWSIG", GPGME_STATUS_NEWSIG },
+-  { "NO_PUBKEY", GPGME_STATUS_NO_PUBKEY },
+-  { "NO_RECP", GPGME_STATUS_NO_RECP },
+-  { "NO_SECKEY", GPGME_STATUS_NO_SECKEY },
+-  { "NO_SGNR", GPGME_STATUS_NO_SGNR },
+   { "NODATA", GPGME_STATUS_NODATA },
+   { "NOTATION_DATA", GPGME_STATUS_NOTATION_DATA },
+   { "NOTATION_FLAGS", GPGME_STATUS_NOTATION_FLAGS },
+   { "NOTATION_NAME", GPGME_STATUS_NOTATION_NAME },
++  { "NO_PUBKEY", GPGME_STATUS_NO_PUBKEY },
++  { "NO_RECP", GPGME_STATUS_NO_RECP },
++  { "NO_SECKEY", GPGME_STATUS_NO_SECKEY },
++  { "NO_SGNR", GPGME_STATUS_NO_SGNR },
+   { "PINENTRY_LAUNCHED", GPGME_STATUS_PINENTRY_LAUNCHED},
+   { "PKA_TRUST_BAD", GPGME_STATUS_PKA_TRUST_BAD },
+   { "PKA_TRUST_GOOD", GPGME_STATUS_PKA_TRUST_GOOD },
+@@ -120,10 +120,10 @@ static struct status_table_s status_table[] =
+   { "SHM_GET_BOOL", GPGME_STATUS_SHM_GET_BOOL },
+   { "SHM_GET_HIDDEN", GPGME_STATUS_SHM_GET_HIDDEN },
+   { "SHM_INFO", GPGME_STATUS_SHM_INFO },
++  { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED },
+   { "SIG_CREATED", GPGME_STATUS_SIG_CREATED },
+   { "SIG_ID", GPGME_STATUS_SIG_ID },
+   { "SIG_SUBPACKET", GPGME_STATUS_SIG_SUBPACKET },
+-  { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED },
+   { "SUCCESS", GPGME_STATUS_SUCCESS },
+   { "TOFU_STATS", GPGME_STATUS_TOFU_STATS },
+   { "TOFU_STATS_LONG", GPGME_STATUS_TOFU_STATS_LONG },
diff --git a/debian/patches/0031-cpp-Fix-CMake-config-library-name-for-GPGME.patch b/debian/patches/0031-cpp-Fix-CMake-config-library-name-for-GPGME.patch
new file mode 100644
index 0000000..a4c5675
--- /dev/null
+++ b/debian/patches/0031-cpp-Fix-CMake-config-library-name-for-GPGME.patch
@@ -0,0 +1,28 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Mon, 12 Jun 2017 15:25:33 +0200
+Subject: cpp: Fix CMake config library name for GPGME
+
+* lang/cpp/src/GpgmeppConfig.cmake.in.in: The link library
+is of course also dynamic.
+
+--
+GnuPG-Bug-Id: T3181
+
+(cherry picked from commit 5c53c702605b8d4458a14e6303cdc13f3b106efa)
+---
+ lang/cpp/src/GpgmeppConfig.cmake.in.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lang/cpp/src/GpgmeppConfig.cmake.in.in b/lang/cpp/src/GpgmeppConfig.cmake.in.in
+index 7f42f31..73f5eaa 100644
+--- a/lang/cpp/src/GpgmeppConfig.cmake.in.in
++++ b/lang/cpp/src/GpgmeppConfig.cmake.in.in
+@@ -63,7 +63,7 @@ add_library(Gpgmepp SHARED IMPORTED)
+ 
+ set_target_properties(Gpgmepp PROPERTIES
+   INTERFACE_INCLUDE_DIRECTORIES "@resolved_includedir@/gpgme++;@resolved_includedir@"
+-  INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme.so;@LIBASSUAN_LIBS@"
++  INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme at libsuffix@;@LIBASSUAN_LIBS@"
+   IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp at libsuffix@"
+ )
+ 
diff --git a/debian/patches/0032-Fix-some-shadow-warnings.patch b/debian/patches/0032-Fix-some-shadow-warnings.patch
new file mode 100644
index 0000000..bc08684
--- /dev/null
+++ b/debian/patches/0032-Fix-some-shadow-warnings.patch
@@ -0,0 +1,38 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Mon, 10 Jul 2017 17:26:46 +0200
+Subject: Fix some shadow warnings
+
+--
+Warnings in headers hurt downstream.
+
+(cherry picked from commit 3b9123b4c64828acd2d2048f40d7631513aeab36)
+---
+ lang/cpp/src/configuration.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/lang/cpp/src/configuration.h b/lang/cpp/src/configuration.h
+index 288a410..5e481a9 100644
+--- a/lang/cpp/src/configuration.h
++++ b/lang/cpp/src/configuration.h
+@@ -93,8 +93,8 @@ class GPGMEPP_EXPORT Component
+ {
+ public:
+     Component() : comp() {}
+-    explicit Component(const shared_gpgme_conf_comp_t &comp)
+-        : comp(comp) {}
++    explicit Component(const shared_gpgme_conf_comp_t &gpgme_comp)
++        : comp(gpgme_comp) {}
+ 
+     // copy ctor is ok
+ 
+@@ -144,8 +144,8 @@ class GPGMEPP_EXPORT Option
+ {
+ public:
+     Option() : comp(), opt(0) {}
+-    Option(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt)
+-        : comp(comp), opt(opt) {}
++    Option(const shared_gpgme_conf_comp_t &gpgme_comp, gpgme_conf_opt_t gpgme_opt)
++        : comp(gpgme_comp), opt(gpgme_opt) {}
+ 
+     const Option &operator=(const Option &other)
+     {
diff --git a/debian/patches/0033-core-Simplify-parsing-of-STATUS_ERROR-in-decrypt.c.patch b/debian/patches/0033-core-Simplify-parsing-of-STATUS_ERROR-in-decrypt.c.patch
new file mode 100644
index 0000000..10f7f90
--- /dev/null
+++ b/debian/patches/0033-core-Simplify-parsing-of-STATUS_ERROR-in-decrypt.c.patch
@@ -0,0 +1,127 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Wed, 12 Jul 2017 15:59:12 +0200
+Subject: core: Simplify parsing of STATUS_ERROR in decrypt.c
+
+* src/decrypt.c (_gpgme_decrypt_status_handler): Factor some code out
+to ...
+(parse_status_error): new.  Modernize parsing.
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+(cherry picked from commit 87703dbb86ac8fd8abd23170f8038ea6e3dbde28)
+---
+ src/conversion.c |  2 +-
+ src/decrypt.c    | 80 +++++++++++++++++++++++++++-----------------------------
+ 2 files changed, 40 insertions(+), 42 deletions(-)
+
+diff --git a/src/conversion.c b/src/conversion.c
+index 92dd214..5b84f67 100644
+--- a/src/conversion.c
++++ b/src/conversion.c
+@@ -374,7 +374,7 @@ _gpgme_encode_percent_string (const char *src, char **destp, size_t len)
+ 
+ 
+ /* Split a string into space delimited fields and remove leading and
+- * trailing spaces from each field.  A pointer to the each field is
++ * trailing spaces from each field.  A pointer to each field is
+  * stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The function
+  * modifies STRING.  The number of parsed fields is returned.
+  */
+diff --git a/src/decrypt.c b/src/decrypt.c
+index f30f80f..cfad35e 100644
+--- a/src/decrypt.c
++++ b/src/decrypt.c
+@@ -124,7 +124,43 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx)
+   return &opd->result;
+ }
+ 
++
+ 

++/* Parse the ARGS of an error status line and record some error
++ * conditions at OPD.  Returns 0 on success.  */
++static gpgme_error_t
++parse_status_error (char *args, op_data_t opd)
++{
++  gpgme_error_t err;
++  char *field[3];
++  int nfields;
++
++  nfields = _gpgme_split_fields (args, field, DIM (field));
++  if (nfields < 1)
++    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing.  */
++  err = nfields < 2 ? 0 : atoi (field[1]);
++
++  if (!strcmp (field[0], "decrypt.algorithm"))
++    {
++      if (gpg_err_code (err) == GPG_ERR_UNSUPPORTED_ALGORITHM
++          && nfields > 2
++          && strcmp (field[2], "?"))
++        {
++          opd->result.unsupported_algorithm = strdup (field[2]);
++          if (!opd->result.unsupported_algorithm)
++            return gpg_error_from_syserror ();
++        }
++    }
++  else if (!strcmp (field[0], "decrypt.keyusage"))
++    {
++      if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
++        opd->result.wrong_key_usage = 1;
++    }
++
++  return 0;
++}
++
++
+ static gpgme_error_t
+ parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol)
+ {
+@@ -230,47 +266,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+       /* Note that this is an informational status code which should
+          not lead to an error return unless it is something not
+          related to the backend.  */
+-      {
+-	const char d_alg[] = "decrypt.algorithm";
+-	const char k_alg[] = "decrypt.keyusage";
+-
+-	if (!strncmp (args, d_alg, sizeof (d_alg) - 1))
+-	  {
+-	    args += sizeof (d_alg) - 1;
+-	    while (*args == ' ')
+-	      args++;
+-
+-	    if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM)
+-	      {
+-		char *end;
+-
+-		while (*args && *args != ' ')
+-		  args++;
+-		while (*args == ' ')
+-		  args++;
+-
+-		end = strchr (args, ' ');
+-		if (end)
+-		  *end = '\0';
+-
+-		if (!(*args == '?' && *(args + 1) == '\0'))
+-		  {
+-		    opd->result.unsupported_algorithm = strdup (args);
+-		    if (!opd->result.unsupported_algorithm)
+-		      return gpg_error_from_syserror ();
+-		  }
+-	      }
+-	  }
+-	else if (!strncmp (args, k_alg, sizeof (k_alg) - 1))
+-	  {
+-	    args += sizeof (k_alg) - 1;
+-	    while (*args == ' ')
+-	      args++;
+-
+-	    if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE)
+-	      opd->result.wrong_key_usage = 1;
+-	  }
+-      }
++      err = parse_status_error (args, opd);
++      if (err)
++        return err;
+       break;
+ 
+     case GPGME_STATUS_ENC_TO:
diff --git a/debian/patches/0034-core-Return-CANCELED-and-BAD_PASSPHRASE-error-code-o.patch b/debian/patches/0034-core-Return-CANCELED-and-BAD_PASSPHRASE-error-code-o.patch
new file mode 100644
index 0000000..7b99d0c
--- /dev/null
+++ b/debian/patches/0034-core-Return-CANCELED-and-BAD_PASSPHRASE-error-code-o.patch
@@ -0,0 +1,78 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Wed, 12 Jul 2017 17:55:43 +0200
+Subject: core: Return CANCELED and BAD_PASSPHRASE error code on decryption.
+
+* src/decrypt.c (op_data_t): Add field pkdecrypt_failed.
+(_gpgme_decrypt_status_handler): Consult new field.
+(parse_status_error): Handle some error codes.
+--
+
+The idea is to return only a limited set of error codes because a user
+won't be able to understand the more esoteric codes.
+
+GnuPG-bug-id: 3270
+Signed-off-by: Werner Koch <wk at gnupg.org>
+(cherry picked from commit d37bc7e025cdc6228da45b2b527e9f3bfef71c71)
+---
+ src/decrypt.c | 33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/src/decrypt.c b/src/decrypt.c
+index cfad35e..3d77aae 100644
+--- a/src/decrypt.c
++++ b/src/decrypt.c
+@@ -43,7 +43,11 @@ typedef struct
+   gpg_error_t failure_code;
+ 
+   int okay;
++
++  /* A flag telling that the a decryption failed and an optional error
++   * code to further specify the failure.  */
+   int failed;
++  gpg_error_t pkdecrypt_failed;
+ 
+   /* A pointer to the next pointer of the last recipient in the list.
+      This makes appending new invalid signers painless while
+@@ -156,6 +160,31 @@ parse_status_error (char *args, op_data_t opd)
+       if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE)
+         opd->result.wrong_key_usage = 1;
+     }
++  else if (!strcmp (field[0], "pkdecrypt_failed"))
++    {
++      switch (gpg_err_code (err))
++        {
++        case GPG_ERR_CANCELED:
++        case GPG_ERR_FULLY_CANCELED:
++          /* It is better to return with a cancel error code than the
++           * general decryption failed error code.  */
++          opd->pkdecrypt_failed = gpg_err_make (gpg_err_source (err),
++                                                GPG_ERR_CANCELED);
++          break;
++
++        case GPG_ERR_BAD_PASSPHRASE:
++          /* A bad passphrase is severe enough that we return this
++           * error code.  */
++          opd->pkdecrypt_failed = err;
++          break;
++
++        default:
++          /* For now all other error codes are ignored and the
++           * standard DECRYPT_FAILED is returned.  */
++          break;
++        }
++    }
++
+ 
+   return 0;
+ }
+@@ -242,7 +271,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+     case GPGME_STATUS_EOF:
+       /* FIXME: These error values should probably be attributed to
+ 	 the underlying crypto engine (as error source).  */
+-      if (opd->failed)
++      if (opd->failed && opd->pkdecrypt_failed)
++        return opd->pkdecrypt_failed;
++      else if (opd->failed)
+ 	return gpg_error (GPG_ERR_DECRYPT_FAILED);
+       else if (!opd->okay)
+ 	return gpg_error (GPG_ERR_NO_DATA);
diff --git a/debian/patches/0035-core-Return-NO_SECKEY-error-code-on-decryption.patch b/debian/patches/0035-core-Return-NO_SECKEY-error-code-on-decryption.patch
new file mode 100644
index 0000000..55d906f
--- /dev/null
+++ b/debian/patches/0035-core-Return-NO_SECKEY-error-code-on-decryption.patch
@@ -0,0 +1,86 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Wed, 12 Jul 2017 18:30:49 +0200
+Subject: core: Return NO_SECKEY error code on decryption
+
+* src/decrypt.c (op_data_t): Add flag any_no_seckey.
+(_gpgme_decrypt_status_handler): Consult that flag.
+(_gpgme_decrypt_status_handler): Set that flag.
+--
+
+The NO_SECKEY is emitted instead of an "S ERROR pkdecrypt_failed" if
+gpg knowns that a key has been encrypted to that key (cf. "S ENC_TO").
+it is not fool proffof but in the majority of cases we can provide a
+better error message than just DECRYPTION_FAILED.
+
+GnuPG-bug-id: 3270
+Signed-off-by: Werner Koch <wk at gnupg.org>
+(cherry picked from commit ad0c5ab4cd8d3a1b11b37dc137b75a67aa26da37)
+---
+ doc/gpgme.texi |  2 +-
+ src/decrypt.c  | 13 +++++++++++--
+ 2 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/doc/gpgme.texi b/doc/gpgme.texi
+index bc40430..31929d3 100644
+--- a/doc/gpgme.texi
++++ b/doc/gpgme.texi
+@@ -4893,7 +4893,7 @@ if @var{ctx}, @var{cipher} or @var{plain} is not a valid pointer,
+ @code{GPG_ERR_NO_DATA} if @var{cipher} does not contain any data to
+ decrypt, @code{GPG_ERR_DECRYPT_FAILED} if @var{cipher} is not a valid
+ cipher text, @code{GPG_ERR_BAD_PASSPHRASE} if the passphrase for the
+-secret key could not be retrieved, and passes through any errors that
++secret key could not be retrieved, and passes through some errors that
+ are reported by the crypto engine support routines.
+ @end deftypefun
+ 
+diff --git a/src/decrypt.c b/src/decrypt.c
+index 3d77aae..118ed70 100644
+--- a/src/decrypt.c
++++ b/src/decrypt.c
+@@ -1,6 +1,6 @@
+ /* decrypt.c - Decrypt function.
+    Copyright (C) 2000 Werner Koch (dd9jn)
+-   Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH
++   Copyright (C) 2001, 2002, 2003, 2004, 2017 g10 Code GmbH
+ 
+    This file is part of GPGME.
+ 
+@@ -49,6 +49,13 @@ typedef struct
+   int failed;
+   gpg_error_t pkdecrypt_failed;
+ 
++  /* At least one secret key is not available.  gpg issues NO_SECKEY
++   * status lines for each key the message has been encrypted to but
++   * that secret key is not available.  This can't be done for hidden
++   * recipients, though.  We track it here to allow for a better error
++   * message that the general DECRYPTION_FAILED. */
++  int any_no_seckey;
++
+   /* A pointer to the next pointer of the last recipient in the list.
+      This makes appending new invalid signers painless while
+      preserving the order.  */
+@@ -273,6 +280,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+ 	 the underlying crypto engine (as error source).  */
+       if (opd->failed && opd->pkdecrypt_failed)
+         return opd->pkdecrypt_failed;
++      else if (opd->failed && opd->any_no_seckey)
++	return gpg_error (GPG_ERR_NO_SECKEY);
+       else if (opd->failed)
+ 	return gpg_error (GPG_ERR_DECRYPT_FAILED);
+       else if (!opd->okay)
+@@ -319,7 +328,6 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+     case GPGME_STATUS_NO_SECKEY:
+       {
+ 	gpgme_recipient_t rec = opd->result.recipients;
+-
+ 	while (rec)
+ 	  {
+ 	    if (!strcmp (rec->keyid, args))
+@@ -332,6 +340,7 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code,
+ 	/* FIXME: Is this ok?  */
+ 	if (!rec)
+ 	  return trace_gpg_error (GPG_ERR_INV_ENGINE);
++        opd->any_no_seckey = 1;
+       }
+       break;
+ 
diff --git a/debian/patches/0036-tests-Fix-printf-compiler-warning-for-an-error-case.patch b/debian/patches/0036-tests-Fix-printf-compiler-warning-for-an-error-case.patch
new file mode 100644
index 0000000..5999d0e
--- /dev/null
+++ b/debian/patches/0036-tests-Fix-printf-compiler-warning-for-an-error-case.patch
@@ -0,0 +1,25 @@
+From: Werner Koch <wk at gnupg.org>
+Date: Wed, 12 Jul 2017 18:32:50 +0200
+Subject: tests: Fix printf compiler warning for an error case.
+
+* tests/gpg/t-keylist.c (main): Cast DIM to int.
+
+Signed-off-by: Werner Koch <wk at gnupg.org>
+(cherry picked from commit 46d2e48105e0929ec38dd4106004dd60d941df9a)
+---
+ tests/gpg/t-keylist.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/gpg/t-keylist.c b/tests/gpg/t-keylist.c
+index 8a32f9b..0417011 100644
+--- a/tests/gpg/t-keylist.c
++++ b/tests/gpg/t-keylist.c
+@@ -569,7 +569,7 @@ main (int argc, char **argv)
+   if (keys[i].fpr)
+     {
+       fprintf (stderr, "Less keys (%d) returned than expected (%d)\n",
+-	       i, DIM (keys) - 1);
++	       i, (int)(DIM (keys) - 1));
+       exit (1);
+     }
+ 
diff --git a/debian/patches/0037-Sync-autogen.sh.patch b/debian/patches/0037-Sync-autogen.sh.patch
new file mode 100644
index 0000000..f93d19e
--- /dev/null
+++ b/debian/patches/0037-Sync-autogen.sh.patch
@@ -0,0 +1,245 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 13 Jul 2017 15:30:38 +0200
+Subject: Sync 'autogen.sh'.
+
+--
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 2446138e3c8c45fd4bd64eba84edd32fcd009699)
+---
+ autogen.sh | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 116 insertions(+), 20 deletions(-)
+
+diff --git a/autogen.sh b/autogen.sh
+index 91f35a6..e5ba5bf 100755
+--- a/autogen.sh
++++ b/autogen.sh
+@@ -1,6 +1,6 @@
+ #! /bin/sh
+ # autogen.sh
+-# Copyright (C) 2003, 2014 g10 Code GmbH
++# Copyright (C) 2003, 2014, 2017 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: 2014-01-10
++# Version: 2017-01-17
+ 
+ configure_ac="configure.ac"
+ 
+@@ -41,7 +41,7 @@ fatal () {
+ 
+ info () {
+     if [ -z "${SILENT}" ]; then
+-      echo "autogen.sh:" "$*"
++      echo "autogen.sh:" "$*" >&2
+     fi
+ }
+ 
+@@ -70,14 +70,27 @@ MSGMERGE=${GETTEXT_PREFIX}${MSGMERGE:-msgmerge}${GETTEXT_SUFFIX}
+ DIE=no
+ FORCE=
+ SILENT=
++PRINT_HOST=no
++PRINT_BUILD=no
+ tmp=$(dirname "$0")
+ tsdir=$(cd "${tmp}"; pwd)
++version_parts=3
+ 
+ if [ -n "${AUTOGEN_SH_SILENT}" ]; then
+   SILENT=" --silent"
+ fi
+ if test x"$1" = x"--help"; then
+-  echo "usage: ./autogen.sh [--silent] [--force] [--build-TYPE] [ARGS]"
++  echo "usage: ./autogen.sh [OPTIONS] [ARGS]"
++  echo "  Options:"
++  echo "    --silent       Silent operation"
++  echo "    --force        Pass --force to autoconf"
++  echo "    --find-version Helper for configure.ac"
++  echo "    --build-TYPE   Configure to cross build for TYPE"
++  echo "    --print-host   Print only the host triplet"
++  echo "    --print-build  Print only the build platform triplet"
++  echo ""
++  echo "  ARGS are passed to configure in --build-TYPE mode."
++  echo "  Configuration for this script is expected in autogen.rc"
+   exit 0
+ fi
+ if test x"$1" = x"--silent"; then
+@@ -88,6 +101,14 @@ if test x"$1" = x"--force"; then
+   FORCE=" --force"
+   shift
+ fi
++if test x"$1" = x"--print-host"; then
++  PRINT_HOST=yes
++  shift
++fi
++if test x"$1" = x"--print-build"; then
++  PRINT_BUILD=yes
++  shift
++fi
+ 
+ 
+ # Reject unsafe characters in $HOME, $tsdir and cwd.  We consider spaces
+@@ -133,6 +154,11 @@ amd64_toolprefixes=
+ myhost=""
+ myhostsub=""
+ case "$1" in
++    --find-version)
++        myhost="find-version"
++        SILENT=" --silent"
++        shift
++        ;;
+     --build-w32)
+         myhost="w32"
+         shift
+@@ -172,16 +198,81 @@ if [ -f "$HOME/.gnupg-autogen.rc" ]; then
+     . "$HOME/.gnupg-autogen.rc"
+ fi
+ 
++
++# **** FIND VERSION ****
++# This is a helper for the configure.ac M4 magic
++# Called
++#   ./autogen.sh --find-version PACKAGE MAJOR MINOR [MICRO]
++# returns a complete version string with automatic beta numbering.
++if [ "$myhost" = "find-version" ]; then
++    package="$1"
++    major="$2"
++    minor="$3"
++    micro="$4"
++
++    if [ -z "$package" -o -z "$major" -o -z "$minor" ]; then
++      echo "usage: ./autogen.sh --find-version PACKAGE MAJOR MINOR [MICRO]" >&2
++      exit 1
++    fi
++
++    case "$version_parts" in
++      2)
++        matchstr1="$package-$major.[0-9]*"
++        matchstr2="$package-$major-base"
++        vers="$major.$minor"
++        ;;
++      *)
++        matchstr1="$package-$major.$minor.[0-9]*"
++        matchstr2="$package-$major.$minor-base"
++        vers="$major.$minor.$micro"
++        ;;
++    esac
++
++    beta=no
++    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}')
++      else
++          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')
++      rvd=$((0x$(echo ${rev} | dd bs=1 count=4 2>/dev/null)))
++    else
++      ingit=no
++      beta=yes
++      tmp="-unknown"
++      rev="0000000"
++      rvd="0"
++    fi
++
++    echo "$package-$vers$tmp:$beta:$ingit:$vers$tmp:$vers:$tmp:$rev:$rvd:"
++    exit 0
++fi
++# **** end FIND VERSION ****
++
++
++if [ ! -f "$tsdir/build-aux/config.guess" ]; then
++    fatal "$tsdir/build-aux/config.guess not found"
++    exit 1
++fi
++build=`$tsdir/build-aux/config.guess`
++if [ $PRINT_BUILD = yes ]; then
++    echo "$build"
++    exit 0
++fi
++
++
++
+ # ******************
+ #  W32 build script
+ # ******************
+ if [ "$myhost" = "w32" ]; then
+-    if [ ! -f "$tsdir/build-aux/config.guess" ]; then
+-        fatal "$tsdir/build-aux/config.guess not found"
+-        exit 1
+-    fi
+-    build=`$tsdir/build-aux/config.guess`
+-
+     case $myhostsub in
+         ce)
+           w32root="$w32ce_root"
+@@ -222,6 +313,10 @@ if [ "$myhost" = "w32" ]; then
+         fi
+         die_p
+     fi
++    if [ $PRINT_HOST = yes ]; then
++        echo "$host"
++        exit 0
++    fi
+ 
+     if [ -f "$tsdir/config.log" ]; then
+         if ! head $tsdir/config.log | grep "$host" >/dev/null; then
+@@ -232,7 +327,8 @@ if [ "$myhost" = "w32" ]; then
+ 
+     $tsdir/configure --enable-maintainer-mode ${SILENT} \
+              --prefix=${w32root}  \
+-             --host=${host} --build=${build} \
++             --host=${host} --build=${build} SYSROOT=${w32root} \
++             PKG_CONFIG_LIBDIR=${w32root}/lib/pkgconfig \
+              ${configure_opts} ${extraoptions} "$@"
+     rc=$?
+     exit $rc
+@@ -242,13 +338,6 @@ fi
+ # ***** AMD64 cross build script *******
+ # Used to cross-compile for AMD64 (for testing)
+ if [ "$myhost" = "amd64" ]; then
+-    shift
+-    if [ ! -f $tsdir/build-aux/config.guess ]; then
+-        echo "$tsdir/build-aux/config.guess not found" >&2
+-        exit 1
+-    fi
+-    build=`$tsdir/build-aux/config.guess`
+-
+     [ -z "$amd64root" ] && amd64root="$HOME/amd64root"
+     info "Using $amd64root as standard install directory"
+     replace_sysroot
+@@ -269,6 +358,10 @@ if [ "$myhost" = "amd64" ]; then
+         echo "Stop." >&2
+         exit 1
+     fi
++    if [ $PRINT_HOST = yes ]; then
++        echo "$host"
++        exit 0
++    fi
+ 
+     if [ -f "$tsdir/config.log" ]; then
+         if ! head $tsdir/config.log | grep "$host" >/dev/null; then
+@@ -341,8 +434,11 @@ fi
+ 
+ # Check the git setup.
+ if [ -d .git ]; then
+-  CP="cp -a"
+-  [ -z "${SILENT}" ] && CP="$CP -v"
++  CP="cp -p"
++  # If we have a GNU cp we can add -v
++  if cp --version >/dev/null 2>/dev/null; then
++    [ -z "${SILENT}" ] && CP="$CP -v"
++  fi
+   if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then
+     [ -z "${SILENT}" ] && cat <<EOF
+ *** Activating trailing whitespace git pre-commit hook. ***
diff --git a/debian/patches/0038-tests-Make-agent-spawning-more-robust.patch b/debian/patches/0038-tests-Make-agent-spawning-more-robust.patch
new file mode 100644
index 0000000..bda4f66
--- /dev/null
+++ b/debian/patches/0038-tests-Make-agent-spawning-more-robust.patch
@@ -0,0 +1,54 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 13 Jul 2017 15:41:11 +0200
+Subject: tests: Make agent spawning more robust.
+
+* tests/gpgsm/Makefile.am (gpgsm.conf): Add agent-program directive.
+* tests/start-stop-agent: Update agent-program directive.
+--
+Update the 'agent-program' configuration directive to point to the
+same agent that we are starting.  Previously, it was possible that a
+different agent was started if 'make check' was run with a different
+PATH.
+
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 9cd2b58dfb2c21cce64520cf4c726859b583d14e)
+---
+ tests/gpgsm/Makefile.am |  1 +
+ tests/start-stop-agent  | 12 ++++++++++++
+ 2 files changed, 13 insertions(+)
+
+diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
+index c73faea..a5667a8 100644
+--- a/tests/gpgsm/Makefile.am
++++ b/tests/gpgsm/Makefile.am
+@@ -65,6 +65,7 @@ BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
+ ./gpgsm.conf:
+ 	echo disable-crl-checks > ./gpgsm.conf
+ 	echo faked-system-time 1008241200 >> ./gpgsm.conf
++	echo "agent-program `which $(GPG_AGENT)`|--debug-quick-random" >> ./gpg.conf
+ 
+ ./private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
+ 	-gpgconf --kill all
+diff --git a/tests/start-stop-agent b/tests/start-stop-agent
+index 3ce6f22..9514e0a 100755
+--- a/tests/start-stop-agent
++++ b/tests/start-stop-agent
+@@ -30,6 +30,18 @@ if [ "$1" = "--stop" ]; then
+   exit 0
+ fi
+ 
++# Update 'agent-program' in the configuration files to make sure we
++# will always start exactly this agent again if we ever need to.
++for F in gpg.conf gpgsm.conf
++do
++  if test -f "$GNUPGHOME/$F"
++  then
++      mv "$GNUPGHOME/$F" "$GNUPGHOME/$F~"
++      sed -e "s#^agent-program.*#agent-program ${GPG_AGENT}|--debug-quick-random#" \
++          >"$GNUPGHOME/$F" <"$GNUPGHOME/$F~"
++  fi
++done
++
+ if [ "$(gpg-connect-agent --no-autostart getval\ $token /bye 2>/dev/null | head -1)" \
+       = "D set" ]; then
+   echo "gpg-agent already running" >&2
diff --git a/debian/patches/0039-tests-Fix-blunder.patch b/debian/patches/0039-tests-Fix-blunder.patch
new file mode 100644
index 0000000..e42f5da
--- /dev/null
+++ b/debian/patches/0039-tests-Fix-blunder.patch
@@ -0,0 +1,25 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 13 Jul 2017 16:04:07 +0200
+Subject: tests: Fix blunder.
+
+--
+Fixes-commit: 9cd2b58dfb2c21cce64520cf4c726859b583d14e
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit ceed4a74540cf2c316b65cf62a9926c65019bb81)
+---
+ tests/gpgsm/Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am
+index a5667a8..274ba9d 100644
+--- a/tests/gpgsm/Makefile.am
++++ b/tests/gpgsm/Makefile.am
+@@ -65,7 +65,7 @@ BUILT_SOURCES = gpgsm.conf trustlist.txt pubring-stamp \
+ ./gpgsm.conf:
+ 	echo disable-crl-checks > ./gpgsm.conf
+ 	echo faked-system-time 1008241200 >> ./gpgsm.conf
+-	echo "agent-program `which $(GPG_AGENT)`|--debug-quick-random" >> ./gpg.conf
++	echo "agent-program `which $(GPG_AGENT)`|--debug-quick-random" >> ./gpgsm.conf
+ 
+ ./private-keys-v1.d/gpg-sample.stamp: $(srcdir)/$(key_id)
+ 	-gpgconf --kill all
diff --git a/debian/patches/0040-tests-Fix-distcheck.patch b/debian/patches/0040-tests-Fix-distcheck.patch
new file mode 100644
index 0000000..037d48d
--- /dev/null
+++ b/debian/patches/0040-tests-Fix-distcheck.patch
@@ -0,0 +1,25 @@
+From: Justus Winter <justus at g10code.com>
+Date: Thu, 13 Jul 2017 16:06:27 +0200
+Subject: tests: Fix distcheck.
+
+* tests/start-stop-agent: Remove backup file.
+
+Fixes-commit: 9cd2b58dfb2c21cce64520cf4c726859b583d14e
+Signed-off-by: Justus Winter <justus at g10code.com>
+(cherry picked from commit 7fde780cc1773c6d3902d4f49a8d4aadbf3223d4)
+---
+ tests/start-stop-agent | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tests/start-stop-agent b/tests/start-stop-agent
+index 9514e0a..7901374 100755
+--- a/tests/start-stop-agent
++++ b/tests/start-stop-agent
+@@ -39,6 +39,7 @@ do
+       mv "$GNUPGHOME/$F" "$GNUPGHOME/$F~"
+       sed -e "s#^agent-program.*#agent-program ${GPG_AGENT}|--debug-quick-random#" \
+           >"$GNUPGHOME/$F" <"$GNUPGHOME/$F~"
++      rm "$GNUPGHOME/$F~"
+   fi
+ done
+ 
diff --git a/debian/patches/0041-core-Fix-status-parsing-for-decrypt-verify.patch b/debian/patches/0041-core-Fix-status-parsing-for-decrypt-verify.patch
new file mode 100644
index 0000000..8384627
--- /dev/null
+++ b/debian/patches/0041-core-Fix-status-parsing-for-decrypt-verify.patch
@@ -0,0 +1,61 @@
+From: Andre Heinecke <aheinecke at intevation.de>
+Date: Thu, 27 Jul 2017 14:20:58 +0200
+Subject: core: Fix status parsing for decrypt + verify
+
+* src/decrypt.c (parse_status_error): Don't modify args.
+
+--
+Otherwise chained status handlers will not see the full args
+which resulted in a parse error in the verify status handler.
+
+GnuPG-Bug-Id: T3310
+(cherry picked from commit d3796e4504a2b4f422de17d78f3acfe8dd199c9c)
+---
+ src/decrypt.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/src/decrypt.c b/src/decrypt.c
+index 118ed70..9717c7a 100644
+--- a/src/decrypt.c
++++ b/src/decrypt.c
+@@ -145,10 +145,18 @@ parse_status_error (char *args, op_data_t opd)
+   gpgme_error_t err;
+   char *field[3];
+   int nfields;
++  char *args2;
+ 
+-  nfields = _gpgme_split_fields (args, field, DIM (field));
++  if (!args)
++    return trace_gpg_error (GPG_ERR_INV_ENGINE);
++
++  args2 = strdup (args); /* Split modifies the input string. */
++  nfields = _gpgme_split_fields (args2, field, DIM (field));
+   if (nfields < 1)
+-    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing.  */
++    {
++      free (args2);
++      return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing.  */
++    }
+   err = nfields < 2 ? 0 : atoi (field[1]);
+ 
+   if (!strcmp (field[0], "decrypt.algorithm"))
+@@ -159,7 +167,10 @@ parse_status_error (char *args, op_data_t opd)
+         {
+           opd->result.unsupported_algorithm = strdup (field[2]);
+           if (!opd->result.unsupported_algorithm)
+-            return gpg_error_from_syserror ();
++            {
++              free (args2);
++              return gpg_error_from_syserror ();
++            }
+         }
+     }
+   else if (!strcmp (field[0], "decrypt.keyusage"))
+@@ -193,6 +204,7 @@ parse_status_error (char *args, op_data_t opd)
+     }
+ 
+ 
++  free (args2);
+   return 0;
+ }
+ 
diff --git a/debian/patches/0042-doc-Add-more-tofu-documentation.patch b/debian/patches/0042-doc-Add-more-tofu-documentation.patch
new file mode 100644
index 0000000..01ee037
--- /dev/null
+++ b/debian/patches/0042-doc-Add-more-tofu-documentation.patch
@@ -0,0 +1,104 @@
+From: Marcus Brinkmann <marcus.brinkmann at ruhr-uni-bochum.de>
+Date: Thu, 10 Aug 2017 16:10:40 +0200
+Subject: doc: Add more tofu documentation.
+
+* doc/gpgme.texi (gpgme_tofu_info_t): Document structure.
+(gpgme_sigsum_t): Document GPGME_SIGSUM_TOFU_CONFLICT.
+
+Signed-off-by: Marcus Brinkmann <mb at g10code.com>
+GnuPG-bug-id: 2816
+(cherry picked from commit 274609baceda3378b21f84c3ae6a44806dad2dba)
+---
+ doc/gpgme.texi | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 72 insertions(+)
+
+diff --git a/doc/gpgme.texi b/doc/gpgme.texi
+index 31929d3..37760af 100644
+--- a/doc/gpgme.texi
++++ b/doc/gpgme.texi
+@@ -3276,6 +3276,75 @@ Reserved for the time of the last update of this user ID.
+ @end deftp
+ 
+ 
++ at deftp {Data type} gpgme_tofu_info_t
++
++The @code{gpgme_tofu_info_t} type is a pointer to a tofu info
++structure.  Tofu info structures are one component of a
++ at code{gpgme_user_id_t} object, and provide information from the TOFU
++database pertaining to the user ID.
++
++The tofu info structure has the following members:
++
++ at table @code
++ at item gpgme_key_sig_t next
++This is a pointer to the next tofu info structure in the linked
++list, or @code{NULL} if this is the last element.
++
++ at item unsigned int validity : 3
++This is the TOFU validity.  It can have the following values:
++
++ at table @code
++ at item 0
++The value @code{0} indicates a conflict.
++
++ at item 1
++The value @code{1} indicates a key without history.
++
++ at item 2
++The value @code{2} indicates a key with too little history.
++
++ at item 3
++The value @code{3} indicates a key with enough history for basic trust.
++
++ at item 4
++The value @code{4} indicates a key with a lot of history.
++
++ at end table
++
++ at item unsigned int policy : 4
++This is the TOFU policy, see @code{gpgme_tofu_policy_t}.
++
++ at item unsigned short signcount
++This is the number of signatures seen for this binding (or
++ at code{USHRT_MAX} if there are more than that).
++
++ at item unsigned short encrcount
++This is the number of encryptions done with this binding (or
++ at code{USHRT_MAX} if there are more than that).
++
++ at item unsigned long signfirst
++Number of seconds since Epoch when the first signature was seen with
++this binding.
++
++ at item unsigned long signlast
++Number of seconds since Epoch when the last signature was seen with
++this binding.
++
++ at item unsigned long encrfirst
++Number of seconds since Epoch when the first encryption was done with
++this binding.
++
++ at item unsigned long encrlast
++Number of seconds since Epoch when the last encryption was done with
++this binding.
++
++ at item char *description
++A human-readable string summarizing the TOFU data (or NULL).
++
++ at end table
++ at end deftp
++
++
+ @deftp {Data type} gpgme_key_sig_t
+ 
+ The @code{gpgme_key_sig_t} type is a pointer to a key signature structure.
+@@ -5196,6 +5265,9 @@ The defined bits are:
+ 
+   @item GPGME_SIGSUM_SYS_ERROR
+   A system error occured.
++
++  @item GPGME_SIGSUM_TOFU_CONFLICT
++  A TOFU conflict was detected.
+   @end table
+ 
+ @item char *fpr
diff --git a/debian/patches/0043-doc-Clarify-import-keys-operation.patch b/debian/patches/0043-doc-Clarify-import-keys-operation.patch
new file mode 100644
index 0000000..1443cf9
--- /dev/null
+++ b/debian/patches/0043-doc-Clarify-import-keys-operation.patch
@@ -0,0 +1,92 @@
+From: Marcus Brinkmann <marcus.brinkmann at ruhr-uni-bochum.de>
+Date: Thu, 10 Aug 2017 16:50:11 +0200
+Subject: doc: Clarify import keys operation.
+
+* doc/gpgme.texi (gpgme_op_import_start): Fix grammar.
+(gpgme_op_import_keys): Clarify some wording and fix result.
+* src/import.c (gpgme_op_import_keys): Clarify comment.
+
+Signed-off-by: Marcus Brinkmann <mb at g10code.com>
+GnuPG-bug-id: 3215
+(cherry picked from commit dfb3ca85680534b3885ab04d3fba4752c5a6f998)
+---
+ doc/gpgme.texi | 28 +++++++++++++---------------
+ src/import.c   | 13 ++++++-------
+ 2 files changed, 19 insertions(+), 22 deletions(-)
+
+diff --git a/doc/gpgme.texi b/doc/gpgme.texi
+index 37760af..bf84629 100644
+--- a/doc/gpgme.texi
++++ b/doc/gpgme.texi
+@@ -4449,34 +4449,32 @@ The function @code{gpgme_op_import_start} initiates a
+ 
+ The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+ import could be started successfully, @code{GPG_ERR_INV_VALUE} if
+- at var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
+-and @code{GPG_ERR_NO_DATA} if @var{keydata} is an empty data buffer.
++ at var{ctx} or @var{keydata} is not a valid pointer, and
++ at code{GPG_ERR_NO_DATA} if @var{keydata} is an empty data buffer.
+ @end deftypefun
+ 
+ @deftypefun gpgme_error_t gpgme_op_import_keys (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
+-The function @code{gpgme_op_import_keys} adds the keys described by the
+- at code{NULL} terminated array @var{keys} to the key ring of the crypto
+-engine used by @var{ctx}.  This function is the general interface to
+-move a key from one crypto engine to another as long as they are
+-compatible.  In particular it is used to actually import and make keys
+-permanent which have been retrieved from an external source (i.e. using
+- at code{GPGME_KEYLIST_MODE_EXTERN}).  @footnote{Thus it is a replacement
+-for the usual workaround of exporting and then importing a key to make
+-an X.509 key permanent.}
++The function @code{gpgme_op_import_keys} adds the keys described by
++the @code{NULL} terminated array @var{keys} to the key ring of the
++crypto engine used by @var{ctx}.  It is used to actually import and
++make keys permanent which have been retrieved from an external source
++(i.e. using @code{GPGME_KEYLIST_MODE_EXTERN}).  @footnote{Thus it is a
++replacement for the usual workaround of exporting and then importing a
++key to make an X.509 key permanent.}
+ 
+ Only keys of the currently selected protocol of @var{ctx} are
+ considered for import.  Other keys specified by the @var{keys} are
+ ignored.  As of now all considered keys must have been retrieved using
+-the same method, that is the used key listing mode must be identical.
++the same method, i.e. the used key listing mode must be identical.
+ 
+ After the operation completed successfully, the result can be
+ retrieved with @code{gpgme_op_import_result}.
+ 
+ The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+ import was completed successfully, @code{GPG_ERR_INV_VALUE} if
+- at var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
+- at code{GPG_ERR_CONFLICT} if the key listing mode does not match, and
+- at code{GPG_ERR_NO_DATA} if no keys are considered for export.
++ at var{ctx} is not a valid pointer, @code{GPG_ERR_CONFLICT} if the key
++listing mode does not match, and @code{GPG_ERR_NO_DATA} if no keys are
++considered for export.
+ @end deftypefun
+ 
+ @deftypefun gpgme_error_t gpgme_op_import_keys_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
+diff --git a/src/import.c b/src/import.c
+index 4173fe9..386ca72 100644
+--- a/src/import.c
++++ b/src/import.c
+@@ -392,13 +392,12 @@ gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys)
+ }
+ 
+ 
+-/* Import the keys from the array KEYS into the keyring.  This
+-   function allows to move a key from one engine to another as long as
+-   they are compatible.  In particular it is used to actually import
+-   keys retrieved from an external source (i.e. using
+-   GPGME_KEYLIST_MODE_EXTERN).  It replaces the old workaround of
+-   exporting and then importing a key as used to make an X.509 key
+-   permanent.  This function automagically does the right thing.
++/* Import the keys from the array KEYS into the keyring.  In
++   particular it is used to actually import keys retrieved from an
++   external source (i.e. using GPGME_KEYLIST_MODE_EXTERN).  It
++   replaces the old workaround of exporting and then importing a key
++   as used to make an X.509 key permanent.  This function
++   automagically does the right thing.
+ 
+    KEYS is a NULL terminated array of gpgme key objects.  The result
+    is the usual import result structure.  Only keys matching the
diff --git a/debian/patches/0044-doc-Clarify-import-keys-operation-further.patch b/debian/patches/0044-doc-Clarify-import-keys-operation-further.patch
new file mode 100644
index 0000000..e96db15
--- /dev/null
+++ b/debian/patches/0044-doc-Clarify-import-keys-operation-further.patch
@@ -0,0 +1,42 @@
+From: Marcus Brinkmann <marcus.brinkmann at ruhr-uni-bochum.de>
+Date: Wed, 16 Aug 2017 15:39:17 +0200
+Subject: doc: Clarify import keys operation further.
+
+* doc/gpgme.texi (gpgme_op_import_keys): Further clarifications.
+
+Signed-off-by: Marcus Brinkmann <mb at g10code.com>
+GnuPG-bug-id: 3215
+(cherry picked from commit 0ee7f4f178284dae153a59be710bc994820369e5)
+---
+ doc/gpgme.texi | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/doc/gpgme.texi b/doc/gpgme.texi
+index bf84629..4829426 100644
+--- a/doc/gpgme.texi
++++ b/doc/gpgme.texi
+@@ -4458,9 +4458,12 @@ The function @code{gpgme_op_import_keys} adds the keys described by
+ the @code{NULL} terminated array @var{keys} to the key ring of the
+ crypto engine used by @var{ctx}.  It is used to actually import and
+ make keys permanent which have been retrieved from an external source
+-(i.e. using @code{GPGME_KEYLIST_MODE_EXTERN}).  @footnote{Thus it is a
++(i.e. using @code{GPGME_KEYLIST_MODE_EXTERN}) earlier.  The external
++keylisting must have been made with the same context configuration (in
++particular the same home directory).  @footnote{Thus it is a
+ replacement for the usual workaround of exporting and then importing a
+-key to make an X.509 key permanent.}
++key to make an X.509 key permanent.}  Note that for OpenPGP this may
++require another access to the keyserver over the network.
+ 
+ Only keys of the currently selected protocol of @var{ctx} are
+ considered for import.  Other keys specified by the @var{keys} are
+@@ -4470,6 +4473,9 @@ the same method, i.e. the used key listing mode must be identical.
+ After the operation completed successfully, the result can be
+ retrieved with @code{gpgme_op_import_result}.
+ 
++To move keys from one home directory to another, export and import the
++keydata using @code{gpgme_op_export} and @code{gpgme_op_import}.
++
+ The function returns the error code @code{GPG_ERR_NO_ERROR} if the
+ import was completed successfully, @code{GPG_ERR_INV_VALUE} if
+ @var{ctx} is not a valid pointer, @code{GPG_ERR_CONFLICT} if the key
diff --git a/debian/patches/series b/debian/patches/series
index 057bc06..765e1ef 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,44 @@
 0001-avoid-identifying-as-beta.patch
 0002-qt-pass-fmt-to-gpgrt_asprintf.patch
+0003-tests-Make-error-message-more-helpful.patch
+0004-python-build-Reinstate-prepare-target.patch
+0005-python-Generate-files-into-build-directory.patch
+0006-python-Fix-vpath-builds-fix-distcheck.patch
+0007-python-simplify-build-some-fixups.patch
+0008-python-support-.pydistutils.cfg-mode.patch
+0009-tests-Do-not-use-check-local-magic-as-dependency.patch
+0010-python-Remove-usage-of-PYTHON_VERSIONS.patch
+0011-python-Remove-unneeded-stats-copy.patch
+0012-python-Read-gpg-error.h-using-the-pre-processor.patch
+0013-python-Support-alternatate-libdir-for-tests.patch
+0014-python-Fix-distcheck.patch
+0015-python-Prune-CLEANFILES.patch
+0016-python-fix-run-tests-missing-python_libdir.patch
+0017-python-use-autoconf-pre-processor-when-building-via-.patch
+0018-tests-Update-encrypted-sample-files.patch
+0019-doc-Improve-doc-on-passphrase_cb-pinentry-mode.patch
+0020-core-Don-t-split-gpgconf-strings-on-comma.patch
+0021-qt-tests-Don-t-use-internal-API.patch
+0022-qt-Undeprecate-API-that-I-find-useful.patch
+0023-qt-Add-a-missing-include-functional.patch
+0024-qt-Stop-agent-on-clean.patch
+0025-tests-Harmonize-test-suites.patch
+0026-tests-Make-sure-to-kill-all-previously-running-daemo.patch
+0027-python-Fix-test-environment-creation.patch
+0028-tests-Remove-remnants-of-check-local.patch
+0029-python-Fix-build-in-certain-cases.patch
+0030-core-Sort-the-status-table.patch
+0031-cpp-Fix-CMake-config-library-name-for-GPGME.patch
+0032-Fix-some-shadow-warnings.patch
+0033-core-Simplify-parsing-of-STATUS_ERROR-in-decrypt.c.patch
+0034-core-Return-CANCELED-and-BAD_PASSPHRASE-error-code-o.patch
+0035-core-Return-NO_SECKEY-error-code-on-decryption.patch
+0036-tests-Fix-printf-compiler-warning-for-an-error-case.patch
+0037-Sync-autogen.sh.patch
+0038-tests-Make-agent-spawning-more-robust.patch
+0039-tests-Fix-blunder.patch
+0040-tests-Fix-distcheck.patch
+0041-core-Fix-status-parsing-for-decrypt-verify.patch
+0042-doc-Add-more-tofu-documentation.patch
+0043-doc-Clarify-import-keys-operation.patch
+0044-doc-Clarify-import-keys-operation-further.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gpgme.git



More information about the Pkg-gnupg-commit mailing list