summaryrefslogtreecommitdiff
path: root/lang
diff options
context:
space:
mode:
Diffstat (limited to 'lang')
-rw-r--r--lang/Makefile.am3
-rw-r--r--lang/Makefile.in54
-rw-r--r--lang/README3
-rw-r--r--lang/cl/Makefile.in50
-rw-r--r--lang/cl/gpgme.asd2
-rw-r--r--lang/cpp/Makefile.am23
-rw-r--r--lang/cpp/Makefile.in709
-rw-r--r--lang/cpp/README101
-rw-r--r--lang/cpp/src/GpgmeppConfig.cmake.in.in108
-rw-r--r--lang/cpp/src/GpgmeppConfigVersion.cmake.in31
-rw-r--r--lang/cpp/src/Makefile.am99
-rw-r--r--lang/cpp/src/Makefile.in955
-rw-r--r--lang/cpp/src/callbacks.cpp149
-rw-r--r--lang/cpp/src/callbacks.h45
-rw-r--r--lang/cpp/src/configuration.cpp934
-rw-r--r--lang/cpp/src/configuration.h290
-rw-r--r--lang/cpp/src/context.cpp1639
-rw-r--r--lang/cpp/src/context.h420
-rw-r--r--lang/cpp/src/context_p.h84
-rw-r--r--lang/cpp/src/context_vanilla.cpp33
-rw-r--r--lang/cpp/src/data.cpp222
-rw-r--r--lang/cpp/src/data.h126
-rw-r--r--lang/cpp/src/data_p.h40
-rw-r--r--lang/cpp/src/decryptionresult.cpp240
-rw-r--r--lang/cpp/src/decryptionresult.h130
-rw-r--r--lang/cpp/src/defaultassuantransaction.cpp78
-rw-r--r--lang/cpp/src/defaultassuantransaction.h65
-rw-r--r--lang/cpp/src/editinteractor.cpp339
-rw-r--r--lang/cpp/src/editinteractor.h68
-rw-r--r--lang/cpp/src/encryptionresult.cpp159
-rw-r--r--lang/cpp/src/encryptionresult.h113
-rw-r--r--lang/cpp/src/engineinfo.cpp88
-rw-r--r--lang/cpp/src/engineinfo.h126
-rw-r--r--lang/cpp/src/error.h78
-rw-r--r--lang/cpp/src/eventloopinteractor.cpp199
-rw-r--r--lang/cpp/src/eventloopinteractor.h156
-rw-r--r--lang/cpp/src/exception.cpp58
-rw-r--r--lang/cpp/src/exception.h68
-rw-r--r--lang/cpp/src/global.h218
-rw-r--r--lang/cpp/src/gpgadduserideditinteractor.cpp189
-rw-r--r--lang/cpp/src/gpgadduserideditinteractor.h67
-rw-r--r--lang/cpp/src/gpgagentgetinfoassuantransaction.cpp119
-rw-r--r--lang/cpp/src/gpgagentgetinfoassuantransaction.h73
-rw-r--r--lang/cpp/src/gpgmefw.h70
-rw-r--r--lang/cpp/src/gpgmepp_export.h73
-rw-r--r--lang/cpp/src/gpgmepp_version.h.in32
-rw-r--r--lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp141
-rw-r--r--lang/cpp/src/gpgsetexpirytimeeditinteractor.h49
-rw-r--r--lang/cpp/src/gpgsetownertrusteditinteractor.cpp151
-rw-r--r--lang/cpp/src/gpgsetownertrusteditinteractor.h50
-rw-r--r--lang/cpp/src/gpgsignkeyeditinteractor.cpp318
-rw-r--r--lang/cpp/src/gpgsignkeyeditinteractor.h64
-rw-r--r--lang/cpp/src/importresult.cpp215
-rw-r--r--lang/cpp/src/importresult.h134
-rw-r--r--lang/cpp/src/interfaces/assuantransaction.h49
-rw-r--r--lang/cpp/src/interfaces/dataprovider.h53
-rw-r--r--lang/cpp/src/interfaces/passphraseprovider.h40
-rw-r--r--lang/cpp/src/interfaces/progressprovider.h40
-rw-r--r--lang/cpp/src/key.cpp912
-rw-r--r--lang/cpp/src/key.h415
-rw-r--r--lang/cpp/src/keygenerationresult.cpp92
-rw-r--r--lang/cpp/src/keygenerationresult.h82
-rw-r--r--lang/cpp/src/keylistresult.cpp107
-rw-r--r--lang/cpp/src/keylistresult.h81
-rw-r--r--lang/cpp/src/notation.h84
-rw-r--r--lang/cpp/src/result.h58
-rw-r--r--lang/cpp/src/result_p.h43
-rw-r--r--lang/cpp/src/scdgetinfoassuantransaction.cpp156
-rw-r--r--lang/cpp/src/scdgetinfoassuantransaction.h76
-rw-r--r--lang/cpp/src/signingresult.cpp265
-rw-r--r--lang/cpp/src/signingresult.h162
-rw-r--r--lang/cpp/src/tofuinfo.cpp167
-rw-r--r--lang/cpp/src/tofuinfo.h124
-rw-r--r--lang/cpp/src/trustitem.cpp114
-rw-r--r--lang/cpp/src/trustitem.h81
-rw-r--r--lang/cpp/src/util.h149
-rw-r--r--lang/cpp/src/verificationresult.cpp575
-rw-r--r--lang/cpp/src/verificationresult.h180
-rw-r--r--lang/cpp/src/vfsmountresult.cpp90
-rw-r--r--lang/cpp/src/vfsmountresult.h76
-rw-r--r--lang/python/MANIFEST.in4
-rw-r--r--lang/python/Makefile.am106
-rw-r--r--lang/python/Makefile.in798
-rw-r--r--lang/python/README59
-rw-r--r--lang/python/examples/assuan.py28
-rw-r--r--lang/python/examples/decryption-filter.py32
-rwxr-xr-xlang/python/examples/delkey.py33
-rwxr-xr-xlang/python/examples/encrypt-to-all.py53
-rwxr-xr-xlang/python/examples/exportimport.py61
-rwxr-xr-xlang/python/examples/genkey.py44
-rw-r--r--lang/python/examples/inter-edit.py56
-rwxr-xr-xlang/python/examples/sign.py28
-rwxr-xr-xlang/python/examples/signverify.py41
-rwxr-xr-xlang/python/examples/simple.py47
-rw-r--r--lang/python/examples/testCMSgetkey.py35
-rwxr-xr-xlang/python/examples/verifydetails.py79
-rwxr-xr-xlang/python/gpgme-h-clean.py53
-rw-r--r--lang/python/gpgme.i625
-rw-r--r--lang/python/helpers.c1169
-rw-r--r--lang/python/helpers.h39
-rw-r--r--lang/python/private.h54
-rw-r--r--lang/python/pyme/__init__.py125
-rw-r--r--lang/python/pyme/__pycache__/__init__.cpython-34.pycbin0 -> 4633 bytes
-rw-r--r--lang/python/pyme/__pycache__/version.cpython-34.pycbin0 -> 1997 bytes
-rw-r--r--lang/python/pyme/callbacks.py49
-rw-r--r--lang/python/pyme/constants/__init__.py114
-rw-r--r--lang/python/pyme/constants/data/__init__.py6
-rw-r--r--lang/python/pyme/constants/data/encoding.py22
-rw-r--r--lang/python/pyme/constants/event.py22
-rw-r--r--lang/python/pyme/constants/import.py22
-rw-r--r--lang/python/pyme/constants/keylist/__init__.py6
-rw-r--r--lang/python/pyme/constants/keylist/mode.py22
-rw-r--r--lang/python/pyme/constants/md.py22
-rw-r--r--lang/python/pyme/constants/pk.py22
-rw-r--r--lang/python/pyme/constants/protocol.py22
-rw-r--r--lang/python/pyme/constants/sig/__init__.py6
-rw-r--r--lang/python/pyme/constants/sig/mode.py22
-rw-r--r--lang/python/pyme/constants/sigsum.py22
-rw-r--r--lang/python/pyme/constants/status.py124
-rw-r--r--lang/python/pyme/constants/validity.py22
-rw-r--r--lang/python/pyme/core.py1145
-rw-r--r--lang/python/pyme/errors.py111
-rw-r--r--lang/python/pyme/gpgme.py125
-rw-r--r--lang/python/pyme/results.py118
-rw-r--r--lang/python/pyme/util.py53
-rw-r--r--lang/python/pyme/version.py68
-rw-r--r--lang/python/pyme/version.py.in68
-rwxr-xr-xlang/python/setup.py.in190
-rw-r--r--lang/python/tests/Makefile.am114
-rw-r--r--lang/python/tests/Makefile.in620
-rw-r--r--lang/python/tests/encrypt-only.asc33
-rwxr-xr-xlang/python/tests/final.py27
-rwxr-xr-xlang/python/tests/initial.py41
-rw-r--r--lang/python/tests/run-tests.py90
-rw-r--r--lang/python/tests/sign-only.asc33
-rw-r--r--lang/python/tests/support.py69
-rwxr-xr-xlang/python/tests/t-callbacks.py257
-rwxr-xr-xlang/python/tests/t-data.py129
-rwxr-xr-xlang/python/tests/t-decrypt-verify.py77
-rwxr-xr-xlang/python/tests/t-decrypt.py45
-rwxr-xr-xlang/python/tests/t-edit.py72
-rwxr-xr-xlang/python/tests/t-encrypt-large.py66
-rwxr-xr-xlang/python/tests/t-encrypt-sign.py98
-rwxr-xr-xlang/python/tests/t-encrypt-sym.py86
-rwxr-xr-xlang/python/tests/t-encrypt.py65
-rwxr-xr-xlang/python/tests/t-export.py40
-rwxr-xr-xlang/python/tests/t-file-name.py45
-rwxr-xr-xlang/python/tests/t-idiomatic.py84
-rwxr-xr-xlang/python/tests/t-import.py79
-rwxr-xr-xlang/python/tests/t-keylist.py246
-rwxr-xr-xlang/python/tests/t-protocol-assuan.py69
-rwxr-xr-xlang/python/tests/t-sig-notation.py79
-rwxr-xr-xlang/python/tests/t-sign.py122
-rwxr-xr-xlang/python/tests/t-signers.py98
-rwxr-xr-xlang/python/tests/t-trustlist.py43
-rwxr-xr-xlang/python/tests/t-verify.py195
-rwxr-xr-xlang/python/tests/t-wait.py45
-rwxr-xr-xlang/python/tests/t-wrapper.py25
-rw-r--r--lang/qt/Makefile.am23
-rw-r--r--lang/qt/Makefile.in709
-rw-r--r--lang/qt/README130
-rw-r--r--lang/qt/doc/Doxyfile.in2352
-rw-r--r--lang/qt/doc/Makefile.am31
-rw-r--r--lang/qt/doc/Makefile.in540
-rw-r--r--lang/qt/src/AddUserIDJob1
-rw-r--r--lang/qt/src/ChangeExpiryJob1
-rw-r--r--lang/qt/src/ChangeOwnerTrustJob1
-rw-r--r--lang/qt/src/ChangePasswdJob1
-rw-r--r--lang/qt/src/CryptoConfig1
-rw-r--r--lang/qt/src/DataProvider1
-rw-r--r--lang/qt/src/DecryptJob1
-rw-r--r--lang/qt/src/DecryptVerifyJob1
-rw-r--r--lang/qt/src/DefaultKeyGenerationJob1
-rw-r--r--lang/qt/src/DeleteJob1
-rw-r--r--lang/qt/src/DownloadJob1
-rw-r--r--lang/qt/src/EncryptJob1
-rw-r--r--lang/qt/src/ExportJob1
-rw-r--r--lang/qt/src/HierarchicalKeyKistJob1
-rw-r--r--lang/qt/src/ImportFromKeyserverJob1
-rw-r--r--lang/qt/src/ImportJob1
-rw-r--r--lang/qt/src/Job1
-rw-r--r--lang/qt/src/KeyForMailboxJob1
-rw-r--r--lang/qt/src/KeyGenerationJob1
-rw-r--r--lang/qt/src/KeyListJob1
-rw-r--r--lang/qt/src/ListAllKeysJob1
-rw-r--r--lang/qt/src/Makefile.am256
-rw-r--r--lang/qt/src/Makefile.in1123
-rw-r--r--lang/qt/src/MultiDeleteJob1
-rw-r--r--lang/qt/src/Protocol1
-rw-r--r--lang/qt/src/QGpgMENewCryptoConfig1
-rw-r--r--lang/qt/src/QGpgmeConfig.cmake.in.in107
-rw-r--r--lang/qt/src/QGpgmeConfigVersion.cmake.in31
-rw-r--r--lang/qt/src/RefreshKeysJob1
-rw-r--r--lang/qt/src/SignEncryptJob1
-rw-r--r--lang/qt/src/SignJob1
-rw-r--r--lang/qt/src/SignKeyJob1
-rw-r--r--lang/qt/src/TofuPolicyJob1
-rw-r--r--lang/qt/src/VerifyDetachedJob1
-rw-r--r--lang/qt/src/VerifyOpaqueJob1
-rw-r--r--lang/qt/src/WKSPublishJob1
-rw-r--r--lang/qt/src/abstractimportjob.h64
-rw-r--r--lang/qt/src/adduseridjob.h84
-rw-r--r--lang/qt/src/changeexpiryjob.h84
-rw-r--r--lang/qt/src/changeownertrustjob.h81
-rw-r--r--lang/qt/src/changepasswdjob.h82
-rw-r--r--lang/qt/src/cryptoconfig.h400
-rw-r--r--lang/qt/src/dataprovider.cpp282
-rw-r--r--lang/qt/src/dataprovider.h95
-rw-r--r--lang/qt/src/decryptjob.h100
-rw-r--r--lang/qt/src/decryptverifyjob.h105
-rw-r--r--lang/qt/src/defaultkeygenerationjob.cpp125
-rw-r--r--lang/qt/src/defaultkeygenerationjob.h76
-rw-r--r--lang/qt/src/deletejob.h83
-rw-r--r--lang/qt/src/downloadjob.h103
-rw-r--r--lang/qt/src/encryptjob.h136
-rw-r--r--lang/qt/src/exportjob.h87
-rw-r--r--lang/qt/src/gpgme_backend_debug.cpp10
-rw-r--r--lang/qt/src/gpgme_backend_debug.h11
-rw-r--r--lang/qt/src/hierarchicalkeylistjob.h125
-rw-r--r--lang/qt/src/importfromkeyserverjob.h84
-rw-r--r--lang/qt/src/importjob.h83
-rw-r--r--lang/qt/src/job.cpp159
-rw-r--r--lang/qt/src/job.h92
-rw-r--r--lang/qt/src/keyformailboxjob.h106
-rw-r--r--lang/qt/src/keygenerationjob.h85
-rw-r--r--lang/qt/src/keylistjob.h109
-rw-r--r--lang/qt/src/listallkeysjob.h104
-rw-r--r--lang/qt/src/multideletejob.h107
-rw-r--r--lang/qt/src/protocol.h183
-rw-r--r--lang/qt/src/protocol_p.h419
-rw-r--r--lang/qt/src/qgpgme_export.h73
-rw-r--r--lang/qt/src/qgpgme_version.h.in32
-rw-r--r--lang/qt/src/qgpgmeadduseridjob.cpp80
-rw-r--r--lang/qt/src/qgpgmeadduseridjob.h65
-rw-r--r--lang/qt/src/qgpgmebackend.cpp203
-rw-r--r--lang/qt/src/qgpgmebackend.h92
-rw-r--r--lang/qt/src/qgpgmechangeexpiryjob.cpp80
-rw-r--r--lang/qt/src/qgpgmechangeexpiryjob.h66
-rw-r--r--lang/qt/src/qgpgmechangeownertrustjob.cpp76
-rw-r--r--lang/qt/src/qgpgmechangeownertrustjob.h65
-rw-r--r--lang/qt/src/qgpgmechangepasswdjob.cpp79
-rw-r--r--lang/qt/src/qgpgmechangepasswdjob.h66
-rw-r--r--lang/qt/src/qgpgmedecryptjob.cpp128
-rw-r--r--lang/qt/src/qgpgmedecryptjob.h84
-rw-r--r--lang/qt/src/qgpgmedecryptverifyjob.cpp135
-rw-r--r--lang/qt/src/qgpgmedecryptverifyjob.h89
-rw-r--r--lang/qt/src/qgpgmedeletejob.cpp65
-rw-r--r--lang/qt/src/qgpgmedeletejob.h71
-rw-r--r--lang/qt/src/qgpgmedownloadjob.cpp100
-rw-r--r--lang/qt/src/qgpgmedownloadjob.h69
-rw-r--r--lang/qt/src/qgpgmeencryptjob.cpp170
-rw-r--r--lang/qt/src/qgpgmeencryptjob.h109
-rw-r--r--lang/qt/src/qgpgmeexportjob.cpp76
-rw-r--r--lang/qt/src/qgpgmeexportjob.h66
-rw-r--r--lang/qt/src/qgpgmeimportfromkeyserverjob.cpp82
-rw-r--r--lang/qt/src/qgpgmeimportfromkeyserverjob.h81
-rw-r--r--lang/qt/src/qgpgmeimportjob.cpp85
-rw-r--r--lang/qt/src/qgpgmeimportjob.h81
-rw-r--r--lang/qt/src/qgpgmekeyformailboxjob.cpp138
-rw-r--r--lang/qt/src/qgpgmekeyformailboxjob.h84
-rw-r--r--lang/qt/src/qgpgmekeygenerationjob.cpp71
-rw-r--r--lang/qt/src/qgpgmekeygenerationjob.h72
-rw-r--r--lang/qt/src/qgpgmekeylistjob.cpp172
-rw-r--r--lang/qt/src/qgpgmekeylistjob.h88
-rw-r--r--lang/qt/src/qgpgmelistallkeysjob.cpp168
-rw-r--r--lang/qt/src/qgpgmelistallkeysjob.h86
-rw-r--r--lang/qt/src/qgpgmenewcryptoconfig.cpp738
-rw-r--r--lang/qt/src/qgpgmenewcryptoconfig.h189
-rw-r--r--lang/qt/src/qgpgmerefreshkeysjob.cpp225
-rw-r--r--lang/qt/src/qgpgmerefreshkeysjob.h79
-rw-r--r--lang/qt/src/qgpgmesecretkeyexportjob.cpp142
-rw-r--r--lang/qt/src/qgpgmesecretkeyexportjob.h81
-rw-r--r--lang/qt/src/qgpgmesignencryptjob.cpp171
-rw-r--r--lang/qt/src/qgpgmesignencryptjob.h121
-rw-r--r--lang/qt/src/qgpgmesignjob.cpp163
-rw-r--r--lang/qt/src/qgpgmesignjob.h101
-rw-r--r--lang/qt/src/qgpgmesignkeyjob.cpp125
-rw-r--r--lang/qt/src/qgpgmesignkeyjob.h94
-rw-r--r--lang/qt/src/qgpgmetofupolicyjob.cpp65
-rw-r--r--lang/qt/src/qgpgmetofupolicyjob.h65
-rw-r--r--lang/qt/src/qgpgmeverifydetachedjob.cpp118
-rw-r--r--lang/qt/src/qgpgmeverifydetachedjob.h85
-rw-r--r--lang/qt/src/qgpgmeverifyopaquejob.cpp125
-rw-r--r--lang/qt/src/qgpgmeverifyopaquejob.h84
-rw-r--r--lang/qt/src/qgpgmewkspublishjob.cpp189
-rw-r--r--lang/qt/src/qgpgmewkspublishjob.h70
-rw-r--r--lang/qt/src/refreshkeysjob.h94
-rw-r--r--lang/qt/src/signencryptjob.h153
-rw-r--r--lang/qt/src/signjob.h122
-rw-r--r--lang/qt/src/signkeyjob.h117
-rw-r--r--lang/qt/src/specialjob.h91
-rw-r--r--lang/qt/src/threadedjobmixin.cpp110
-rw-r--r--lang/qt/src/threadedjobmixin.h272
-rw-r--r--lang/qt/src/tofupolicyjob.h80
-rw-r--r--lang/qt/src/verifydetachedjob.h99
-rw-r--r--lang/qt/src/verifyopaquejob.h101
-rw-r--r--lang/qt/src/wkspublishjob.h101
-rw-r--r--lang/qt/tests/Makefile.am95
-rw-r--r--lang/qt/tests/Makefile.in951
-rwxr-xr-xlang/qt/tests/initial.test2
-rw-r--r--lang/qt/tests/run-keyformailboxjob.cpp56
-rw-r--r--lang/qt/tests/t-encrypt.cpp254
-rw-r--r--lang/qt/tests/t-keylist.cpp107
-rw-r--r--lang/qt/tests/t-keylocate.cpp130
-rw-r--r--lang/qt/tests/t-ownertrust.cpp107
-rw-r--r--lang/qt/tests/t-support.cpp95
-rw-r--r--lang/qt/tests/t-support.h63
-rw-r--r--lang/qt/tests/t-tofuinfo.cpp367
-rw-r--r--lang/qt/tests/t-wkspublish.cpp278
309 files changed, 42589 insertions, 14 deletions
diff --git a/lang/Makefile.am b/lang/Makefile.am
index 854d934..fd3ce4e 100644
--- a/lang/Makefile.am
+++ b/lang/Makefile.am
@@ -17,6 +17,7 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-SUBDIRS = cl
+SUBDIRS = $(ENABLED_LANGUAGES)
+DIST_SUBDIRS = cl cpp qt python
EXTRA_DIST = README
diff --git a/lang/Makefile.in b/lang/Makefile.in
index 3dc49d0..5c96b8f 100644
--- a/lang/Makefile.in
+++ b/lang/Makefile.in
@@ -100,12 +100,16 @@ subdir = lang
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/build-aux/mkinstalldirs README
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
- $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnupg-ttyname.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
$(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -167,7 +171,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -208,6 +211,7 @@ BUILD_REVISION = @BUILD_REVISION@
BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
@@ -219,12 +223,14 @@ CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
@@ -235,15 +241,23 @@ GLIB_LIBS = @GLIB_LIBS@
GLIB_MKENUMS = @GLIB_MKENUMS@
GOBJECT_QUERY = @GOBJECT_QUERY@
GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -254,10 +268,16 @@ LDFLAGS = @LDFLAGS@
LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
@@ -267,6 +287,8 @@ MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -283,14 +305,27 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
-QT4_CORE_CFLAGS = @QT4_CORE_CFLAGS@
-QT4_CORE_LIBS = @QT4_CORE_LIBS@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
RANLIB = @RANLIB@
RC = @RC@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
SYSROOT = @SYSROOT@
VERSION = @VERSION@
VERSION_NUMBER = @VERSION_NUMBER@
@@ -339,9 +374,13 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@@ -350,7 +389,8 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-SUBDIRS = cl
+SUBDIRS = $(ENABLED_LANGUAGES)
+DIST_SUBDIRS = cl cpp qt python
EXTRA_DIST = README
all: all-recursive
diff --git a/lang/README b/lang/README
index da54c78..f7a1595 100644
--- a/lang/README
+++ b/lang/README
@@ -10,3 +10,6 @@ sub-directory.
Directory Language
cl Common Lisp
+cpp C++
+qt Qt-Framework API
+python Python 2 and 3 (port of PyME 0.9.0)
diff --git a/lang/cl/Makefile.in b/lang/cl/Makefile.in
index 954fc18..7a79757 100644
--- a/lang/cl/Makefile.in
+++ b/lang/cl/Makefile.in
@@ -103,12 +103,16 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/build-aux/mkinstalldirs $(srcdir)/gpgme.asd.in \
$(dist_clfiles_DATA) README
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \
- $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnupg-ttyname.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
$(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
- $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -180,6 +184,7 @@ BUILD_REVISION = @BUILD_REVISION@
BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
@@ -191,12 +196,14 @@ CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
@@ -207,15 +214,23 @@ GLIB_LIBS = @GLIB_LIBS@
GLIB_MKENUMS = @GLIB_MKENUMS@
GOBJECT_QUERY = @GOBJECT_QUERY@
GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -226,10 +241,16 @@ LDFLAGS = @LDFLAGS@
LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
@@ -239,6 +260,8 @@ MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -255,14 +278,27 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
-QT4_CORE_CFLAGS = @QT4_CORE_CFLAGS@
-QT4_CORE_LIBS = @QT4_CORE_LIBS@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
RANLIB = @RANLIB@
RC = @RC@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
SYSROOT = @SYSROOT@
VERSION = @VERSION@
VERSION_NUMBER = @VERSION_NUMBER@
@@ -311,9 +347,13 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
diff --git a/lang/cl/gpgme.asd b/lang/cl/gpgme.asd
index 9030a65..c192da7 100644
--- a/lang/cl/gpgme.asd
+++ b/lang/cl/gpgme.asd
@@ -27,7 +27,7 @@
(defsystem gpgme
:description "GnuPG Made Easy."
:author "g10 Code GmbH"
- :version "1.6.0"
+ :version "1.7.0"
:licence "GPL"
:depends-on ("cffi" "gpg-error")
:components ((:file "gpgme-package")
diff --git a/lang/cpp/Makefile.am b/lang/cpp/Makefile.am
new file mode 100644
index 0000000..7fbaca8
--- /dev/null
+++ b/lang/cpp/Makefile.am
@@ -0,0 +1,23 @@
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+SUBDIRS = src
+
+EXTRA_DIST = README
diff --git a/lang/cpp/Makefile.in b/lang/cpp/Makefile.in
new file mode 100644
index 0000000..f042f77
--- /dev/null
+++ b/lang/cpp/Makefile.in
@@ -0,0 +1,709 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/cpp
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = src
+EXTRA_DIST = README
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/cpp/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/cpp/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/cpp/README b/lang/cpp/README
new file mode 100644
index 0000000..b9a48da
--- /dev/null
+++ b/lang/cpp/README
@@ -0,0 +1,101 @@
+GpgMEpp - C++ bindings/wrapper for GPGME
+----------------------------------------
+Based on KF5gpgmepp
+
+Overview
+--------
+
+GpgMEpp is a C++ wrapper (or C++ bindings) for the GnuPG project's
+gpgme (GnuPG Made Easy) library, version 0.4.4 and later.
+
+It is fairly complete, with some minor things still missing (in
+particular, the key edit interface).
+
+The design principles of this library are as follows:
+
+1. A value-based interface (most clases are implicitly shared)
+2. Callbacks are replaced by C++ interfaces (classes with only
+ abstract methods).
+3. No exceptions are thrown
+4. There is (as yet) no explicit support for multi-threaded use
+ (other than what gpgme itself provides; most notably the
+ refcounting for implicit sharing is not thread-safe)
+5. To avoid binary incompatible interface changes, we make
+ extensive use of the d-pointer pattern and avoid virtual
+ methods; any polymorphism present is already provided by gpgme
+ itself, anyway (see e.g. Data). A notable exception of the
+ no-virtuals rule is the use of abstract classes to cover
+ C-callbacks.
+6. Use of STL containers for improved memory management and
+ dealing with lists.
+7. Complete abstraction of the C-API so "gpgme.h" should not
+ be needed in your project using GpgME++.
+8. Abstraction of GnuPG's edit-key interface by prepared
+ Editinteractor classes.
+
+GpgMEpp was originally developed as part of the KDEPIM community.
+
+Usage
+-----
+
+The usage pattern of GpgMEpp closely follows GPGMEs core usage
+pattern so the documentation for GPGME itself provides a good
+way to start.
+
+The context structure in GPGME is mapped to a Context object in
+GpgMEpp. Additional convienience code provides Data objects and
+a Dataprovider interface that can be used to implement GPGME's
+data with any subclass by implementing the right callbacks.
+
+EditInteractor subclasses provide ready to use classes for
+common --edit-key tasks. You can implement your own editinteractor
+classes by implementing the EditInteractor interface and using
+your subclass as an interactor in the edit function.
+
+Example to set the ownertrust of a key:
+
+ /* Create an edit interactor */
+ EditInteractor *ei = new GpgSetOwnerTrustEditInteractor(Key::Ultimate);
+ /* Obtain a Context */
+ Context *ctx = Context::createForProtocol(Protocol::OpenPGP);
+ /* Create an in memory data object */
+ Data data;
+ /* Start the edit on some key previously obtained. */
+ Error e = ctx->edit(key, std::unique_ptr<EditInteractor>(ei), data);
+ /* Errors provide boolean comparision */
+ if (!e)
+ ...
+ /* Delete the context */
+ delete ctx;
+
+Examples / Tests
+----------------
+
+GpgMEpp is tested through the Qt API. You can refer to the
+tests in qt/tests for examples of usage or refer to
+the actual QGpgME*Job.cpp implementations which rely
+on GpgMEpp and should cover most use cases.
+
+Hacking
+-------
+
+GpgMEpp follows KDE Coding styles. See:
+https://techbase.kde.org/Policies/Frameworks_Coding_Style
+for more info.
+
+License
+-------
+GPGMEpp is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+GPGMEpp is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License
+along with GPGME++; see the file COPYING.LIB. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
diff --git a/lang/cpp/src/GpgmeppConfig.cmake.in.in b/lang/cpp/src/GpgmeppConfig.cmake.in.in
new file mode 100644
index 0000000..d54011e
--- /dev/null
+++ b/lang/cpp/src/GpgmeppConfig.cmake.in.in
@@ -0,0 +1,108 @@
+# CMake Config file for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+# based on a generated file from cmake.
+# Generated by CMake 3.0.2
+
+if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
+ message(FATAL_ERROR "CMake >= 2.6.0 required")
+endif()
+cmake_policy(PUSH)
+cmake_policy(VERSION 2.6)
+#----------------------------------------------------------------
+# Generated CMake target import file.
+#----------------------------------------------------------------
+
+# Commands may need to know the format version.
+set(CMAKE_IMPORT_FILE_VERSION 1)
+
+# Protect against multiple inclusion, which would fail when already imported targets are added once more.
+set(_targetsDefined)
+set(_targetsNotDefined)
+set(_expectedTargets)
+foreach(_expectedTarget KF5::Gpgmepp Gpgmepp)
+ list(APPEND _expectedTargets ${_expectedTarget})
+ if(NOT TARGET ${_expectedTarget})
+ list(APPEND _targetsNotDefined ${_expectedTarget})
+ endif()
+ if(TARGET ${_expectedTarget})
+ list(APPEND _targetsDefined ${_expectedTarget})
+ endif()
+endforeach()
+if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
+ set(CMAKE_IMPORT_FILE_VERSION)
+ cmake_policy(POP)
+ return()
+endif()
+if(NOT "${_targetsDefined}" STREQUAL "")
+ message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
+endif()
+unset(_targetsDefined)
+unset(_targetsNotDefined)
+unset(_expectedTargets)
+
+# Compute the installation prefix relative to this file.
+get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+
+# Create imported target Gpgmepp
+add_library(Gpgmepp SHARED IMPORTED)
+
+set_target_properties(Gpgmepp PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include/gpgme++"
+ INTERFACE_LINK_LIBRARIES "pthread;@resolved_libdir@/libgpgme@libsuffix@;@LIBASSUAN_LIBS@"
+ IMPORTED_LOCATION "@resolved_libdir@/libgpgmepp@libsuffix@"
+)
+
+if(CMAKE_VERSION VERSION_LESS 2.8.12)
+ message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
+endif()
+
+# Cleanup temporary variables.
+set(_IMPORT_PREFIX)
+
+# Loop over all imported files and verify that they actually exist
+foreach(target ${_IMPORT_CHECK_TARGETS} )
+ foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
+ if(NOT EXISTS "${file}" )
+ message(FATAL_ERROR "The imported target \"${target}\" references the file
+ \"${file}\"
+but this file does not exist. Possible reasons include:
+* The file was deleted, renamed, or moved to another location.
+* An install or uninstall procedure did not complete successfully.
+* The installation package was faulty and contained
+ \"${CMAKE_CURRENT_LIST_FILE}\"
+but not all the files it references.
+")
+ endif()
+ endforeach()
+ unset(_IMPORT_CHECK_FILES_FOR_${target})
+endforeach()
+unset(_IMPORT_CHECK_TARGETS)
+
+# Commands beyond this point should not need to know the version.
+set(CMAKE_IMPORT_FILE_VERSION)
+cmake_policy(POP)
+
+get_filename_component(QGpgme_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+# Pull in QGpgme for compatibility with KF5 variant.
+find_package(QGpgme CONFIG)
diff --git a/lang/cpp/src/GpgmeppConfigVersion.cmake.in b/lang/cpp/src/GpgmeppConfigVersion.cmake.in
new file mode 100644
index 0000000..43d6512
--- /dev/null
+++ b/lang/cpp/src/GpgmeppConfigVersion.cmake.in
@@ -0,0 +1,31 @@
+# CMake Version file for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+# based on a generated file from cmake.
+set(PACKAGE_VERSION "@LIBGPGMEPP_LT_CURRENT@.@LIBGPGMEPP_LT_AGE@.@LIBGPGMEPP_LT_REVISION@.@BUILD_REVISION@")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/lang/cpp/src/Makefile.am b/lang/cpp/src/Makefile.am
new file mode 100644
index 0000000..e65a875
--- /dev/null
+++ b/lang/cpp/src/Makefile.am
@@ -0,0 +1,99 @@
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+EXTRA_DIST = GpgmeppConfig.cmake.in.in GpgmeppConfigVersion.cmake.in \
+ gpgmepp_version.h.in
+
+lib_LTLIBRARIES = libgpgmepp.la
+
+main_sources = \
+ exception.cpp context.cpp key.cpp trustitem.cpp data.cpp callbacks.cpp \
+ eventloopinteractor.cpp editinteractor.cpp \
+ keylistresult.cpp keygenerationresult.cpp importresult.cpp \
+ decryptionresult.cpp verificationresult.cpp \
+ signingresult.cpp encryptionresult.cpp \
+ engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \
+ gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \
+ gpgadduserideditinteractor.cpp defaultassuantransaction.cpp \
+ scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \
+ vfsmountresult.cpp configuration.cpp tofuinfo.cpp
+
+gpgmepp_headers = \
+ configuration.h context.h data.h decryptionresult.h \
+ defaultassuantransaction.h editinteractor.h encryptionresult.h \
+ engineinfo.h error.h eventloopinteractor.h exception.h global.h \
+ gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \
+ gpgmefw.h gpgsetexpirytimeeditinteractor.h \
+ gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \
+ importresult.h keygenerationresult.h key.h keylistresult.h \
+ notation.h result.h scdgetinfoassuantransaction.h signingresult.h \
+ trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \
+ tofuinfo.h
+
+private_gpgmepp_headers = \
+ result_p.h context_p.h util.h callbacks.h data_p.h
+
+interface_headers= \
+ interfaces/assuantransaction.h interfaces/dataprovider.h \
+ interfaces/passphraseprovider.h interfaces/progressprovider.h
+
+gpgmeppincludedir = $(includedir)/gpgme++
+gpgmeppinclude_HEADERS = $(gpgmepp_headers)
+nobase_gpgmeppinclude_HEADERS = $(interface_headers)
+nodist_include_HEADERS = gpgmepp_version.h
+
+libgpgmepp_la_SOURCES = $(main_sources) $(gpgmepp_headers) context_vanilla.cpp \
+ $(interface_headers) $(private_gpgmepp_headers)
+
+AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
+ -DBUILDING_GPGMEPP
+
+libgpgmepp_la_LIBADD = ../../../src/libgpgme.la @LIBASSUAN_LIBS@
+libgpgmepp_la_LDFLAGS = -version-info \
+ @LIBGPGMEPP_LT_CURRENT@:@LIBGPGMEPP_LT_REVISION@:@LIBGPGMEPP_LT_AGE@
+
+if HAVE_W32_SYSTEM
+libsuffix=.dll.a
+else
+libsuffix=.so
+endif
+
+GpgmeppConfig.cmake: GpgmeppConfig.cmake.in
+ sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@"
+ sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2
+ mv "$@".2 "$@"
+
+install-cmake-files: GpgmeppConfig.cmake GpgmeppConfigVersion.cmake
+ -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp
+ $(INSTALL) GpgmeppConfig.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
+ $(INSTALL) GpgmeppConfigVersion.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
+
+uninstall-cmake-files:
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
+ -rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/
+
+install-data-local: install-cmake-files
+
+uninstall-local: uninstall-cmake-files
+
+CLEANFILES = GpgmeppConfig.cmake
diff --git a/lang/cpp/src/Makefile.in b/lang/cpp/src/Makefile.in
new file mode 100644
index 0000000..9237d27
--- /dev/null
+++ b/lang/cpp/src/Makefile.in
@@ -0,0 +1,955 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/cpp/src
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs \
+ $(srcdir)/GpgmeppConfig.cmake.in.in \
+ $(srcdir)/GpgmeppConfigVersion.cmake.in \
+ $(srcdir)/gpgmepp_version.h.in $(top_srcdir)/build-aux/depcomp \
+ $(gpgmeppinclude_HEADERS) $(nobase_gpgmeppinclude_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = GpgmeppConfig.cmake.in GpgmeppConfigVersion.cmake \
+ gpgmepp_version.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(gpgmeppincludedir)" \
+ "$(DESTDIR)$(gpgmeppincludedir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libgpgmepp_la_DEPENDENCIES = ../../../src/libgpgme.la
+am__objects_1 = exception.lo context.lo key.lo trustitem.lo data.lo \
+ callbacks.lo eventloopinteractor.lo editinteractor.lo \
+ keylistresult.lo keygenerationresult.lo importresult.lo \
+ decryptionresult.lo verificationresult.lo signingresult.lo \
+ encryptionresult.lo engineinfo.lo \
+ gpgsetexpirytimeeditinteractor.lo \
+ gpgsetownertrusteditinteractor.lo gpgsignkeyeditinteractor.lo \
+ gpgadduserideditinteractor.lo defaultassuantransaction.lo \
+ scdgetinfoassuantransaction.lo \
+ gpgagentgetinfoassuantransaction.lo vfsmountresult.lo \
+ configuration.lo tofuinfo.lo
+am__objects_2 =
+am_libgpgmepp_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
+ context_vanilla.lo $(am__objects_2) $(am__objects_2)
+libgpgmepp_la_OBJECTS = $(am_libgpgmepp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgpgmepp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgpgmepp_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgpgmepp_la_SOURCES)
+DIST_SOURCES = $(libgpgmepp_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(gpgmeppinclude_HEADERS) $(nobase_gpgmeppinclude_HEADERS) \
+ $(nodist_include_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = GpgmeppConfig.cmake.in.in GpgmeppConfigVersion.cmake.in \
+ gpgmepp_version.h.in
+
+lib_LTLIBRARIES = libgpgmepp.la
+main_sources = \
+ exception.cpp context.cpp key.cpp trustitem.cpp data.cpp callbacks.cpp \
+ eventloopinteractor.cpp editinteractor.cpp \
+ keylistresult.cpp keygenerationresult.cpp importresult.cpp \
+ decryptionresult.cpp verificationresult.cpp \
+ signingresult.cpp encryptionresult.cpp \
+ engineinfo.cpp gpgsetexpirytimeeditinteractor.cpp \
+ gpgsetownertrusteditinteractor.cpp gpgsignkeyeditinteractor.cpp \
+ gpgadduserideditinteractor.cpp defaultassuantransaction.cpp \
+ scdgetinfoassuantransaction.cpp gpgagentgetinfoassuantransaction.cpp \
+ vfsmountresult.cpp configuration.cpp tofuinfo.cpp
+
+gpgmepp_headers = \
+ configuration.h context.h data.h decryptionresult.h \
+ defaultassuantransaction.h editinteractor.h encryptionresult.h \
+ engineinfo.h error.h eventloopinteractor.h exception.h global.h \
+ gpgadduserideditinteractor.h gpgagentgetinfoassuantransaction.h \
+ gpgmefw.h gpgsetexpirytimeeditinteractor.h \
+ gpgsetownertrusteditinteractor.h gpgsignkeyeditinteractor.h \
+ importresult.h keygenerationresult.h key.h keylistresult.h \
+ notation.h result.h scdgetinfoassuantransaction.h signingresult.h \
+ trustitem.h verificationresult.h vfsmountresult.h gpgmepp_export.h \
+ tofuinfo.h
+
+private_gpgmepp_headers = \
+ result_p.h context_p.h util.h callbacks.h data_p.h
+
+interface_headers = \
+ interfaces/assuantransaction.h interfaces/dataprovider.h \
+ interfaces/passphraseprovider.h interfaces/progressprovider.h
+
+gpgmeppincludedir = $(includedir)/gpgme++
+gpgmeppinclude_HEADERS = $(gpgmepp_headers)
+nobase_gpgmeppinclude_HEADERS = $(interface_headers)
+nodist_include_HEADERS = gpgmepp_version.h
+libgpgmepp_la_SOURCES = $(main_sources) $(gpgmepp_headers) context_vanilla.cpp \
+ $(interface_headers) $(private_gpgmepp_headers)
+
+AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
+ -DBUILDING_GPGMEPP
+
+libgpgmepp_la_LIBADD = ../../../src/libgpgme.la @LIBASSUAN_LIBS@
+libgpgmepp_la_LDFLAGS = -version-info \
+ @LIBGPGMEPP_LT_CURRENT@:@LIBGPGMEPP_LT_REVISION@:@LIBGPGMEPP_LT_AGE@
+
+@HAVE_W32_SYSTEM_FALSE@libsuffix = .so
+@HAVE_W32_SYSTEM_TRUE@libsuffix = .dll.a
+CLEANFILES = GpgmeppConfig.cmake
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/cpp/src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/cpp/src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+GpgmeppConfig.cmake.in: $(top_builddir)/config.status $(srcdir)/GpgmeppConfig.cmake.in.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+GpgmeppConfigVersion.cmake: $(top_builddir)/config.status $(srcdir)/GpgmeppConfigVersion.cmake.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+gpgmepp_version.h: $(top_builddir)/config.status $(srcdir)/gpgmepp_version.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgpgmepp.la: $(libgpgmepp_la_OBJECTS) $(libgpgmepp_la_DEPENDENCIES) $(EXTRA_libgpgmepp_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgpgmepp_la_LINK) -rpath $(libdir) $(libgpgmepp_la_OBJECTS) $(libgpgmepp_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callbacks.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/configuration.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context_vanilla.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decryptionresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defaultassuantransaction.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/editinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encryptionresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/engineinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eventloopinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exception.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgadduserideditinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgagentgetinfoassuantransaction.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsetexpirytimeeditinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsetownertrusteditinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsignkeyeditinteractor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/importresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keygenerationresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keylistresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scdgetinfoassuantransaction.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signingresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tofuinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trustitem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verificationresult.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vfsmountresult.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-gpgmeppincludeHEADERS: $(gpgmeppinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(gpgmeppinclude_HEADERS)'; test -n "$(gpgmeppincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(gpgmeppincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(gpgmeppincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(gpgmeppincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(gpgmeppincludedir)" || exit $$?; \
+ done
+
+uninstall-gpgmeppincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(gpgmeppinclude_HEADERS)'; test -n "$(gpgmeppincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(gpgmeppincludedir)'; $(am__uninstall_files_from_dir)
+install-nobase_gpgmeppincludeHEADERS: $(nobase_gpgmeppinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nobase_gpgmeppinclude_HEADERS)'; test -n "$(gpgmeppincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(gpgmeppincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(gpgmeppincludedir)" || exit 1; \
+ fi; \
+ $(am__nobase_list) | while read dir files; do \
+ xfiles=; for file in $$files; do \
+ if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+ test -z "$$xfiles" || { \
+ test "x$$dir" = x. || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(gpgmeppincludedir)/$$dir'"; \
+ $(MKDIR_P) "$(DESTDIR)$(gpgmeppincludedir)/$$dir"; }; \
+ echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(gpgmeppincludedir)/$$dir'"; \
+ $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(gpgmeppincludedir)/$$dir" || exit $$?; }; \
+ done
+
+uninstall-nobase_gpgmeppincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nobase_gpgmeppinclude_HEADERS)'; test -n "$(gpgmeppincludedir)" || list=; \
+ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+ dir='$(DESTDIR)$(gpgmeppincludedir)'; $(am__uninstall_files_from_dir)
+install-nodist_includeHEADERS: $(nodist_include_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-nodist_includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(gpgmeppincludedir)" "$(DESTDIR)$(gpgmeppincludedir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-gpgmeppincludeHEADERS \
+ install-nobase_gpgmeppincludeHEADERS \
+ install-nodist_includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-gpgmeppincludeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-local uninstall-nobase_gpgmeppincludeHEADERS \
+ uninstall-nodist_includeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-gpgmeppincludeHEADERS \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man \
+ install-nobase_gpgmeppincludeHEADERS \
+ install-nodist_includeHEADERS install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am \
+ uninstall-gpgmeppincludeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-local uninstall-nobase_gpgmeppincludeHEADERS \
+ uninstall-nodist_includeHEADERS
+
+
+GpgmeppConfig.cmake: GpgmeppConfig.cmake.in
+ sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@"
+ sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2
+ mv "$@".2 "$@"
+
+install-cmake-files: GpgmeppConfig.cmake GpgmeppConfigVersion.cmake
+ -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp
+ $(INSTALL) GpgmeppConfig.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
+ $(INSTALL) GpgmeppConfigVersion.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
+
+uninstall-cmake-files:
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfigVersion.cmake
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/GpgmeppConfig.cmake
+ -rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/
+
+install-data-local: install-cmake-files
+
+uninstall-local: uninstall-cmake-files
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/cpp/src/callbacks.cpp b/lang/cpp/src/callbacks.cpp
new file mode 100644
index 0000000..4b4dd80
--- /dev/null
+++ b/lang/cpp/src/callbacks.cpp
@@ -0,0 +1,149 @@
+/*
+ callbacks.cpp - callback targets for internal use:
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "callbacks.h"
+#include "util.h"
+
+#include <interfaces/progressprovider.h>
+#include <interfaces/passphraseprovider.h>
+#include <interfaces/dataprovider.h>
+#include <error.h>
+
+#include <gpgme.h>
+#include <gpg-error.h>
+
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <unistd.h>
+#include <stdlib.h>
+
+static inline gpgme_error_t make_err_from_syserror()
+{
+ return gpgme_error_from_syserror();
+}
+
+using GpgME::ProgressProvider;
+using GpgME::PassphraseProvider;
+using GpgME::DataProvider;
+
+void progress_callback(void *opaque, const char *what,
+ int type, int current, int total)
+{
+ ProgressProvider *provider = static_cast<ProgressProvider *>(opaque);
+ if (provider) {
+ provider->showProgress(what, type, current, total);
+ }
+}
+
+/* To avoid that a compiler optimizes certain memset calls away, these
+ macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+ volatile char *_vptr=(volatile char *)(_ptr); \
+ size_t _vlen=(_len); \
+ while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+ } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint, const char *desc,
+ int prev_was_bad, int fd)
+{
+ PassphraseProvider *provider = static_cast<PassphraseProvider *>(opaque);
+ bool canceled = false;
+ gpgme_error_t err = GPG_ERR_NO_ERROR;
+ char *passphrase = provider ? provider->getPassphrase(uid_hint, desc, prev_was_bad, canceled) : 0 ;
+ if (canceled) {
+ err = make_error(GPG_ERR_CANCELED);
+ } else {
+ if (passphrase && *passphrase) {
+ size_t passphrase_length = std::strlen(passphrase);
+ size_t written = 0;
+ do {
+ ssize_t now_written = gpgme_io_write(fd, passphrase + written, passphrase_length - written);
+ if (now_written < 0) {
+ err = make_err_from_syserror();
+ break;
+ }
+ written += now_written;
+ } while (written < passphrase_length);
+ }
+ }
+
+ if (passphrase && *passphrase) {
+ wipememory(passphrase, std::strlen(passphrase));
+ }
+ free(passphrase);
+ gpgme_io_write(fd, "\n", 1);
+ return err;
+}
+
+static gpgme_ssize_t
+data_read_callback(void *opaque, void *buf, size_t buflen)
+{
+ DataProvider *provider = static_cast<DataProvider *>(opaque);
+ if (!provider) {
+ gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+ return -1;
+ }
+ return (gpgme_ssize_t)provider->read(buf, buflen);
+}
+
+static gpgme_ssize_t
+data_write_callback(void *opaque, const void *buf, size_t buflen)
+{
+ DataProvider *provider = static_cast<DataProvider *>(opaque);
+ if (!provider) {
+ gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+ return -1;
+ }
+ return (gpgme_ssize_t)provider->write(buf, buflen);
+}
+
+static gpgme_off_t
+data_seek_callback(void *opaque, gpgme_off_t offset, int whence)
+{
+ DataProvider *provider = static_cast<DataProvider *>(opaque);
+ if (!provider) {
+ gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+ return -1;
+ }
+ if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
+ gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
+ return -1;
+ }
+ return provider->seek((off_t)offset, whence);
+}
+
+static void data_release_callback(void *opaque)
+{
+ DataProvider *provider = static_cast<DataProvider *>(opaque);
+ if (provider) {
+ provider->release();
+ }
+}
+
+const gpgme_data_cbs GpgME::data_provider_callbacks = {
+ &data_read_callback,
+ &data_write_callback,
+ &data_seek_callback,
+ &data_release_callback
+};
diff --git a/lang/cpp/src/callbacks.h b/lang/cpp/src/callbacks.h
new file mode 100644
index 0000000..4206637
--- /dev/null
+++ b/lang/cpp/src/callbacks.h
@@ -0,0 +1,45 @@
+/*
+ callbacks.h - callback targets for internal use:
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ This is an internal header file, subject to change without
+ notice. DO NOT USE.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_CALLBACKS_H__
+#define __GPGMEPP_CALLBACKS_H__
+
+#include <gpgme.h>
+
+extern "C" {
+
+ void progress_callback(void *opaque, const char *what,
+ int type, int current, int total);
+ gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint,
+ const char *desc, int prev_was_bad, int fd);
+}
+
+namespace GpgME
+{
+extern const gpgme_data_cbs data_provider_callbacks;
+extern const gpgme_edit_cb_t edit_interactor_callback;
+}
+
+#endif // __GPGME_CALLBACKS_H__
diff --git a/lang/cpp/src/configuration.cpp b/lang/cpp/src/configuration.cpp
new file mode 100644
index 0000000..7ef2883
--- /dev/null
+++ b/lang/cpp/src/configuration.cpp
@@ -0,0 +1,934 @@
+/*
+ configuration.cpp - wraps gpgme configuration components
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "configuration.h"
+#include "error.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <iterator>
+#include <algorithm>
+#include <ostream>
+#include <cstring>
+#include <assert.h>
+
+using namespace GpgME;
+using namespace GpgME::Configuration;
+
+typedef std::shared_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t;
+typedef std::weak_ptr< std::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t;
+
+typedef std::shared_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t;
+typedef std::weak_ptr< std::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t;
+
+typedef std::shared_ptr< std::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t;
+typedef std::weak_ptr< std::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t;
+
+namespace
+{
+struct nodelete {
+ template <typename T> void operator()(T *) {}
+};
+}
+
+// static
+std::vector<Component> Component::load(Error &returnedError)
+{
+
+ //
+ // 1. get a context:
+ //
+ gpgme_ctx_t ctx_native = 0;
+ if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
+ returnedError = Error(err);
+ return std::vector<Component>();
+ }
+ const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
+
+ //
+ // 2. load the config:
+ //
+ gpgme_conf_comp_t conf_list_native = 0;
+ if (const gpgme_error_t err = gpgme_op_conf_load(ctx_native, &conf_list_native)) {
+ returnedError = Error(err);
+ return std::vector<Component>();
+ }
+ shared_gpgme_conf_comp_t head(conf_list_native, &gpgme_conf_release);
+
+ //
+ // 3. convert to vector<Component>:
+ //
+ std::vector<Component> result;
+
+ while (head) {
+ // secure 'head->next' (if any) against memleaks:
+ shared_gpgme_conf_comp_t next;
+ if (head->next) {
+ next.reset(head->next, &gpgme_conf_release);
+ }
+
+ // now prevent double-free of next.get() and following:
+ head->next = 0;
+
+ // now add a new Component to 'result' (may throw):
+ result.resize(result.size() + 1);
+ result.back().comp.swap(head); // .comp = std::move( head );
+ head.swap(next); // head = std::move( next );
+ }
+
+ return result;
+}
+
+Error Component::save() const
+{
+
+ if (isNull()) {
+ return Error(make_error(GPG_ERR_INV_ARG));
+ }
+
+ //
+ // 1. get a context:
+ //
+ gpgme_ctx_t ctx_native = 0;
+ if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
+ return Error(err);
+ }
+ const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
+
+ //
+ // 2. save the config:
+ //
+ return Error(gpgme_op_conf_save(ctx.get(), comp.get()));
+}
+
+const char *Component::name() const
+{
+ return comp ? comp->name : 0 ;
+}
+
+const char *Component::description() const
+{
+ return comp ? comp->description : 0 ;
+}
+
+const char *Component::programName() const
+{
+ return comp ? comp->program_name : 0 ;
+}
+
+Option Component::option(unsigned int idx) const
+{
+ gpgme_conf_opt_t opt = 0;
+ if (comp) {
+ opt = comp->options;
+ }
+ while (opt && idx) {
+ opt = opt->next;
+ --idx;
+ }
+ if (opt) {
+ return Option(comp, opt);
+ }
+ return Option();
+}
+
+Option Component::option(const char *name) const
+{
+ gpgme_conf_opt_t opt = 0;
+ if (comp) {
+ opt = comp->options;
+ }
+ using namespace std; // for strcmp
+ while (opt && strcmp(name, opt->name) != 0) {
+ opt = opt->next;
+ }
+ if (opt) {
+ return Option(comp, opt);
+ }
+ return Option();
+}
+
+unsigned int Component::numOptions() const
+{
+ unsigned int result = 0;
+ for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
+ ++result;
+ }
+ return result;
+}
+
+std::vector<Option> Component::options() const
+{
+ std::vector<Option> result;
+ for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
+ result.push_back(Option(comp, opt));
+ }
+ return result;
+}
+
+static gpgme_conf_arg_t mygpgme_conf_arg_copy(gpgme_conf_arg_t other, gpgme_conf_type_t type)
+{
+ gpgme_conf_arg_t result = 0, last = 0;
+ for (gpgme_conf_arg_t a = other ; a ; a = a->next) {
+ gpgme_conf_arg_t arg = 0;
+ const gpgme_error_t err
+ = gpgme_conf_arg_new(&arg, type,
+ a->no_arg ? 0 :
+ type == GPGME_CONF_STRING ? a->value.string :
+ /* else */ static_cast<void *>(&a->value));
+ if (err) {
+ gpgme_conf_arg_release(result, type);
+ return 0;
+ }
+ assert(arg);
+ if (result) {
+ last->next = arg;
+ } else {
+ result = arg;
+ }
+ last = arg;
+ }
+ return result;
+}
+
+Component Option::parent() const
+{
+ return Component(comp.lock());
+}
+
+unsigned int Option::flags() const
+{
+ return isNull() ? 0 : opt->flags;
+}
+
+Level Option::level() const
+{
+ return isNull() ? Internal : static_cast<Level>(opt->level) ;
+}
+
+const char *Option::name() const
+{
+ return isNull() ? 0 : opt->name ;
+}
+
+const char *Option::description() const
+{
+ return isNull() ? 0 : opt->description ;
+}
+
+const char *Option::argumentName() const
+{
+ return isNull() ? 0 : opt->argname ;
+}
+
+Type Option::type() const
+{
+ return isNull() ? NoType : static_cast<Type>(opt->type) ;
+}
+
+Type Option::alternateType() const
+{
+ return isNull() ? NoType : static_cast<Type>(opt->alt_type) ;
+}
+
+#if 0
+static Option::Variant argument_to_variant(gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg)
+{
+ assert(arg);
+ switch (type) {
+ case GPGME_CONF_NONE:
+ if (list) {
+ // return the count (number of times set):
+ return arg->value.count;
+ } else {
+ return none;
+ }
+ case GPGME_CONF_INT32:
+ if (list) {
+ std::vector<int> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.int32);
+ }
+ return result;
+ } else {
+ return arg->value.int32;
+ }
+ case GPGME_CONF_UINT32:
+ if (list) {
+ std::vector<unsigned int> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.uint32);
+ }
+ return result;
+ } else {
+ return arg->value.uint32;
+ }
+ case GPGME_CONF_FILENAME:
+ case GPGME_CONF_LDAP_SERVER:
+ case GPGME_CONF_KEY_FPR:
+ case GPGME_CONF_PUB_KEY:
+ case GPGME_CONF_SEC_KEY:
+ case GPGME_CONF_ALIAS_LIST:
+ // these should not happen in alt_type, but fall through
+ case GPGME_CONF_STRING:
+ if (list) {
+ std::vector<const char *> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.string);
+ }
+ return result;
+ } else {
+ return arg->value.string;
+ }
+ }
+ assert(!"Option: unknown alt_type!");
+ return Option::Variant();
+}
+
+namespace
+{
+inline const void *to_void_star(const char *s)
+{
+ return s;
+}
+inline const void *to_void_star(const std::string &s)
+{
+ return s.c_str();
+}
+inline const void *to_void_star(const int &i)
+{
+ return &i; // const-&: sic!
+}
+inline const void *to_void_star(const unsigned int &i)
+{
+ return &i; // const-&: sic!
+}
+
+struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> {
+ static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
+ {
+ gpgme_conf_arg_t arg = 0;
+#ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
+ if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
+ return 0;
+ }
+#else
+ if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) {
+ return 0;
+ }
+#endif
+ else {
+ return arg;
+ }
+ }
+
+ gpgme_conf_arg_t operator()(bool v) const
+ {
+ return v ? make_argument(0) : 0 ;
+ }
+
+ gpgme_conf_arg_t operator()(const char *s) const
+ {
+ return make_argument(s ? s : "");
+ }
+
+ gpgme_conf_arg_t operator()(const std::string &s) const
+ {
+ return operator()(s.c_str());
+ }
+
+ gpgme_conf_arg_t operator()(int i) const
+ {
+ return make_argument(&i);
+ }
+
+ gpgme_conf_arg_t operator()(unsigned int i) const
+ {
+ return make_argument(&i);
+ }
+
+ template <typename T>
+ gpgme_conf_arg_t operator()(const std::vector<T> &value) const
+ {
+ gpgme_conf_arg_t result = 0;
+ gpgme_conf_arg_t last = 0;
+ for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
+ if (gpgme_conf_arg_t arg = make_argument(to_void_star(*it))) {
+ if (last) {
+ last = last->next = arg;
+ } else {
+ result = last = arg;
+ }
+ }
+ }
+ return result;
+ }
+
+};
+}
+
+static gpgme_conf_arg_t variant_to_argument(const Option::Variant &value)
+{
+ VariantToArgumentVisitor v;
+ return apply_visitor(v, value);
+}
+
+optional<Option::Variant> Option::defaultValue() const
+{
+ if (isNull()) {
+ return optional<Variant>();
+ } else {
+ return argument_to_variant(opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value);
+ }
+}
+#endif
+
+Argument Option::defaultValue() const
+{
+ if (isNull()) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, opt->default_value, false);
+ }
+}
+
+const char *Option::defaultDescription() const
+{
+ return isNull() ? 0 : opt->default_description ;
+}
+
+Argument Option::noArgumentValue() const
+{
+ if (isNull()) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, opt->no_arg_value, false);
+ }
+}
+
+const char *Option::noArgumentDescription() const
+{
+ return isNull() ? 0 : opt->no_arg_description ;
+}
+
+Argument Option::activeValue() const
+{
+ if (isNull()) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, opt->value, false);
+ }
+}
+
+Argument Option::currentValue() const
+{
+ if (isNull()) {
+ return Argument();
+ }
+ const gpgme_conf_arg_t arg =
+ opt->change_value ? opt->new_value ? opt->new_value : opt->default_value :
+ opt->value ? opt->value :
+ /* else */ opt->default_value ;
+ return Argument(comp.lock(), opt, arg, false);
+}
+
+Argument Option::newValue() const
+{
+ if (isNull()) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, opt->new_value, false);
+ }
+}
+
+bool Option::set() const
+{
+ if (isNull()) {
+ return false;
+ } else if (opt->change_value) {
+ return opt->new_value;
+ } else {
+ return opt->value;
+ }
+}
+
+bool Option::dirty() const
+{
+ return !isNull() && opt->change_value ;
+}
+
+Error Option::setNewValue(const Argument &argument)
+{
+ if (isNull()) {
+ return Error(make_error(GPG_ERR_INV_ARG));
+ } else if (argument.isNull()) {
+ return resetToDefaultValue();
+ } else if (const gpgme_conf_arg_t arg = mygpgme_conf_arg_copy(argument.arg, opt->alt_type)) {
+ return Error(gpgme_conf_opt_change(opt, 0, arg));
+ } else {
+ return Error(make_error(GPG_ERR_ENOMEM));
+ }
+}
+
+Error Option::resetToActiveValue()
+{
+ if (isNull()) {
+ return Error(make_error(GPG_ERR_INV_ARG));
+ } else {
+ return Error(gpgme_conf_opt_change(opt, 1, 0));
+ }
+}
+
+Error Option::resetToDefaultValue()
+{
+ if (isNull()) {
+ return Error(make_error(GPG_ERR_INV_ARG));
+ } else {
+ return Error(gpgme_conf_opt_change(opt, 0, 0));
+ }
+}
+
+static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
+{
+ gpgme_conf_arg_t arg = 0;
+ if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
+ return 0;
+ } else {
+ return arg;
+ }
+}
+
+Argument Option::createNoneArgument(bool set) const
+{
+ if (isNull() || alternateType() != NoType) {
+ return Argument();
+ } else {
+ if (set) {
+ return createNoneListArgument(1);
+ }
+ }
+ return Argument();
+}
+
+Argument Option::createStringArgument(const char *value) const
+{
+ if (isNull() || alternateType() != StringType) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+ }
+}
+
+Argument Option::createStringArgument(const std::string &value) const
+{
+ if (isNull() || alternateType() != StringType) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value.c_str()), true);
+ }
+}
+
+Argument Option::createIntArgument(int value) const
+{
+ if (isNull() || alternateType() != IntegerType) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, &value), true);
+ }
+}
+
+Argument Option::createUIntArgument(unsigned int value) const
+{
+ if (isNull() || alternateType() != UnsignedIntegerType) {
+ return Argument();
+ } else {
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, &value), true);
+ }
+}
+
+namespace
+{
+const void *to_void_star(const char *s)
+{
+ return s;
+}
+const void *to_void_star(const std::string &s)
+{
+ return s.c_str();
+}
+const void *to_void_star(const int &i)
+{
+ return &i; // const-&: sic!
+}
+const void *to_void_star(const unsigned int &i)
+{
+ return &i; // const-&: sic!
+}
+
+template <typename T>
+gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const std::vector<T> &value)
+{
+ gpgme_conf_arg_t result = 0;
+ gpgme_conf_arg_t last = 0;
+ for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
+ if (gpgme_conf_arg_t arg = make_argument(type, to_void_star(*it))) {
+ if (last) {
+ last = last->next = arg;
+ } else {
+ result = last = arg;
+ }
+ }
+ }
+ return result;
+}
+}
+
+Argument Option::createNoneListArgument(unsigned int value) const
+{
+ if (value) {
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_NONE, &value), true);
+ }
+ return Argument();
+}
+
+Argument Option::createStringListArgument(const std::vector<const char *> &value) const
+{
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+}
+
+Argument Option::createStringListArgument(const std::vector<std::string> &value) const
+{
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
+}
+
+Argument Option::createIntListArgument(const std::vector<int> &value) const
+{
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, value), true);
+}
+
+Argument Option::createUIntListArgument(const std::vector<unsigned int> &value) const
+{
+ return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, value), true);
+}
+
+Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns)
+ : comp(comp),
+ opt(opt),
+ arg(owns ? arg : mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+{
+
+}
+
+#if 0
+Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg)
+ : comp(comp),
+ opt(opt),
+ arg(mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+{
+
+}
+#endif
+
+Argument::Argument(const Argument &other)
+ : comp(other.comp),
+ opt(other.opt),
+ arg(mygpgme_conf_arg_copy(other.arg, opt ? opt->alt_type : GPGME_CONF_NONE))
+{
+
+}
+
+Argument::~Argument()
+{
+ gpgme_conf_arg_release(arg, opt ? opt->alt_type : GPGME_CONF_NONE);
+}
+
+Option Argument::parent() const
+{
+ return Option(comp.lock(), opt);
+}
+
+bool Argument::boolValue() const
+{
+ return numberOfTimesSet();
+}
+
+unsigned int Argument::numElements() const
+{
+ if (isNull()) {
+ return 0;
+ }
+ unsigned int result = 0;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ ++result;
+ }
+ return result;
+}
+
+const char *Argument::stringValue(unsigned int idx) const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
+ return 0;
+ }
+ gpgme_conf_arg_t a = arg;
+ while (a && idx) {
+ a = a->next;
+ --idx;
+ }
+ return a ? a->value.string : 0 ;
+}
+
+int Argument::intValue(unsigned int idx) const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
+ return 0;
+ }
+ gpgme_conf_arg_t a = arg;
+ while (a && idx) {
+ a = a->next;
+ --idx;
+ }
+ return a ? a->value.int32 : 0 ;
+}
+
+unsigned int Argument::uintValue(unsigned int idx) const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
+ return 0;
+ }
+ gpgme_conf_arg_t a = arg;
+ while (a && idx) {
+ a = a->next;
+ --idx;
+ }
+ return a ? a->value.uint32 : 0 ;
+}
+
+unsigned int Argument::numberOfTimesSet() const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_NONE) {
+ return 0;
+ }
+ return arg->value.count;
+}
+
+std::vector<const char *> Argument::stringValues() const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
+ return std::vector<const char *>();
+ }
+ std::vector<const char *> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.string);
+ }
+ return result;
+}
+
+std::vector<int> Argument::intValues() const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
+ return std::vector<int>();
+ }
+ std::vector<int> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.int32);
+ }
+ return result;
+}
+
+std::vector<unsigned int> Argument::uintValues() const
+{
+ if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
+ return std::vector<unsigned int>();
+ }
+ std::vector<unsigned int> result;
+ for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
+ result.push_back(a->value.uint32);
+ }
+ return result;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Level level)
+{
+ switch (level) {
+ case Basic: return os << "Basic";
+ case Advanced: return os << "Advanced";
+ case Expert: return os << "Expert";
+ case Invisible: return os << "Invisible";
+ case Internal: return os << "Internal";
+ case NumLevels: ;
+ }
+ return os << "<unknown>";
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Type type)
+{
+ switch (type) {
+ case NoType: return os << "None";
+ case StringType: return os << "String";
+ case IntegerType: return os << "Integer";
+ case UnsignedIntegerType: return os << "UnsignedInteger";
+ case FilenameType: return os << "Filename";
+ case LdapServerType: return os << "LdapServer";
+ case KeyFingerprintType: return os << "KeyFingerprint";
+ case PublicKeyType: return os << "PublicKey";
+ case SecretKeyType: return os << "SecretKey";
+ case AliasListType: return os << "AliasList";
+ case MaxType: ;
+ }
+ return os << "<unknown>";
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, Flag f)
+{
+ unsigned int flags = f;
+ std::vector<const char *> s;
+ if (flags & Group) {
+ s.push_back("Group");
+ }
+ if (flags & Optional) {
+ s.push_back("Optional");
+ }
+ if (flags & List) {
+ s.push_back("List");
+ }
+ if (flags & Runtime) {
+ s.push_back("Runtime");
+ }
+ if (flags & Default) {
+ s.push_back("Default");
+ }
+ if (flags & DefaultDescription) {
+ s.push_back("DefaultDescription");
+ }
+ if (flags & NoArgumentDescription) {
+ s.push_back("NoArgumentDescription");
+ }
+ if (flags & NoChange) {
+ s.push_back("NoChange");
+ }
+ flags &= ~(Group | Optional | List | Runtime | Default | DefaultDescription | NoArgumentDescription | NoChange);
+ if (flags) {
+ s.push_back("other flags(");
+ }
+ std::copy(s.begin(), s.end(),
+ std::ostream_iterator<const char *>(os, "|"));
+ if (flags) {
+ os << flags << ')';
+ }
+ return os;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Component &c)
+{
+ os << "Component["
+ << "\n name : " << protect(c.name())
+ << "\n description: " << protect(c.description())
+ << "\n programName: " << protect(c.programName())
+ << "\n options : \n";
+ const std::vector<Option> options = c.options();
+ std::copy(options.begin(), options.end(),
+ std::ostream_iterator<Option>(os, "\n"));
+ os << "\n]";
+ return os;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Option &o)
+{
+ return os << "Option["
+ << "\n name: : " << protect(o.name())
+ << "\n description : " << protect(o.description())
+ << "\n argName : " << protect(o.argumentName())
+ << "\n flags : " << static_cast<Flag>(o.flags())
+ << "\n level : " << o.level()
+ << "\n type : " << o.type()
+ << "\n alt_type : " << o.alternateType()
+ << "\n default_val : " << o.defaultValue()
+ << "\n default_desc: " << protect(o.defaultDescription())
+ << "\n no_arg_value: " << o.noArgumentValue()
+ << "\n no_arg_desc : " << protect(o.noArgumentDescription())
+ << "\n active_value: " << o.activeValue()
+ << "\n new_value : " << o.newValue()
+ << "\n --> cur_val : " << o.currentValue()
+ << "\n set : " << o.set()
+ << "\n dirty : " << o.dirty()
+ << "\n]"
+ ;
+}
+
+std::ostream &Configuration::operator<<(std::ostream &os, const Argument &a)
+{
+ const Option o = a.parent();
+ const bool list = o.flags() & List;
+ os << "Argument[";
+ if (a) {
+ switch (o.alternateType()) {
+ case NoType:
+ if (list) {
+ os << a.numberOfTimesSet() << 'x';
+ } else {
+ os << a.boolValue();
+ }
+ break;
+ default:
+ case StringType:
+ if (list) {
+ const std::vector<const char *> v = a.stringValues();
+ os << v.size() << ':';
+ // can't use std::copy + ostream_iterator here, since we need the protect() call
+ bool first = true;
+ std::for_each(v.begin(), v.end(), [&first, &os](const char *s) {
+ if (first) {
+ first = false;
+ } else {
+ os << ',';
+ }
+ os << protect(s);
+ });
+ } else {
+ os << protect(a.stringValue());
+ }
+ break;
+ case IntegerType:
+ if (list) {
+ const std::vector<int> v = a.intValues();
+ os << v.size() << ':';
+ std::copy(v.begin(), v.end(),
+ std::ostream_iterator<int>(os, ","));
+ } else {
+ os << a.intValue();
+ }
+ break;
+ case UnsignedIntegerType:
+ if (list) {
+ const std::vector<unsigned int> v = a.uintValues();
+ os << v.size() << ':';
+ std::copy(v.begin(), v.end(),
+ std::ostream_iterator<unsigned int>(os, ","));
+ } else {
+ os << a.intValue();
+ }
+ break;
+ }
+ }
+ return os << ']';
+}
diff --git a/lang/cpp/src/configuration.h b/lang/cpp/src/configuration.h
new file mode 100644
index 0000000..288a410
--- /dev/null
+++ b/lang/cpp/src/configuration.h
@@ -0,0 +1,290 @@
+/*
+ configuration.h - wraps gpgme configuration components
+ Copyright (C) 2010 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONFIGURATION_H__
+#define __GPGMEPP_CONFIGURATION_H__
+
+#include "global.h"
+
+#include "gpgmefw.h"
+
+#include <iosfwd>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <memory>
+
+namespace GpgME
+{
+namespace Configuration
+{
+
+typedef std::shared_ptr< std::remove_pointer<gpgme_conf_comp_t>::type > shared_gpgme_conf_comp_t;
+typedef std::weak_ptr< std::remove_pointer<gpgme_conf_comp_t>::type > weak_gpgme_conf_comp_t;
+
+class Argument;
+class Option;
+class Component;
+
+enum Level {
+ Basic,
+ Advanced,
+ Expert,
+ Invisible,
+ Internal,
+
+ NumLevels
+};
+
+enum Type {
+ NoType,
+ StringType,
+ IntegerType,
+ UnsignedIntegerType,
+
+ FilenameType = 32,
+ LdapServerType,
+ KeyFingerprintType,
+ PublicKeyType,
+ SecretKeyType,
+ AliasListType,
+
+ MaxType
+};
+
+enum Flag {
+ Group = (1 << 0),
+ Optional = (1 << 1),
+ List = (1 << 2),
+ Runtime = (1 << 3),
+ Default = (1 << 4),
+ DefaultDescription = (1 << 5),
+ NoArgumentDescription = (1 << 6),
+ NoChange = (1 << 7),
+
+ LastFlag = NoChange
+};
+
+//
+// class Component
+//
+
+class GPGMEPP_EXPORT Component
+{
+public:
+ Component() : comp() {}
+ explicit Component(const shared_gpgme_conf_comp_t &comp)
+ : comp(comp) {}
+
+ // copy ctor is ok
+
+ const Component &operator=(const Component &other)
+ {
+ if (this != &other) {
+ Component(other).swap(*this);
+ }
+ return *this;
+ }
+
+ void swap(Component &other)
+ {
+ using std::swap;
+ swap(this->comp, other.comp);
+ }
+
+ bool isNull() const
+ {
+ return !comp;
+ }
+
+ static std::vector<Component> load(Error &err);
+ Error save() const;
+
+ const char *name() const;
+ const char *description() const;
+ const char *programName() const;
+
+ Option option(unsigned int index) const;
+ Option option(const char *name) const;
+
+ unsigned int numOptions() const;
+
+ std::vector<Option> options() const;
+
+ GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+ shared_gpgme_conf_comp_t comp;
+};
+
+//
+// class Option
+//
+
+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) {}
+
+ const Option &operator=(const Option &other)
+ {
+ if (this != &other) {
+ Option(other).swap(*this);
+ }
+ return *this;
+ }
+
+ void swap(Option &other)
+ {
+ using std::swap;
+ swap(this->comp, other.comp);
+ swap(this->opt, other.opt);
+ }
+
+ bool isNull() const
+ {
+ return comp.expired() || !opt;
+ }
+
+ Component parent() const;
+
+ unsigned int flags() const;
+
+ Level level() const;
+
+ const char *name() const;
+ const char *description() const;
+ const char *argumentName() const;
+
+ Type type() const;
+ Type alternateType() const;
+
+ Argument defaultValue() const;
+ const char *defaultDescription() const;
+
+ Argument noArgumentValue() const;
+ const char *noArgumentDescription() const;
+
+ /*! The value that is in the config file (or null, if it's not set). */
+ Argument activeValue() const;
+ /*! The value that is in this object, ie. either activeValue(), newValue(), or defaultValue() */
+ Argument currentValue() const;
+
+ Argument newValue() const;
+ bool set() const;
+ bool dirty() const;
+
+ Error setNewValue(const Argument &argument);
+ Error resetToDefaultValue();
+ Error resetToActiveValue();
+
+ Argument createNoneArgument(bool set) const;
+ Argument createStringArgument(const char *value) const;
+ Argument createStringArgument(const std::string &value) const;
+ Argument createIntArgument(int value) const;
+ Argument createUIntArgument(unsigned int value) const;
+
+ Argument createNoneListArgument(unsigned int count) const;
+ Argument createStringListArgument(const std::vector<const char *> &value) const;
+ Argument createStringListArgument(const std::vector<std::string> &value) const;
+ Argument createIntListArgument(const std::vector<int> &values) const;
+ Argument createUIntListArgument(const std::vector<unsigned int> &values) const;
+
+ GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+ weak_gpgme_conf_comp_t comp;
+ gpgme_conf_opt_t opt;
+};
+
+//
+// class Argument
+//
+
+class GPGMEPP_EXPORT Argument
+{
+ friend class ::GpgME::Configuration::Option;
+ Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns);
+public:
+ Argument() : comp(), opt(0), arg(0) {}
+ //Argument( const shared_gpgme_conf_comp_t & comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg );
+ Argument(const Argument &other);
+ ~Argument();
+
+ const Argument &operator=(const Argument &other)
+ {
+ if (this != &other) {
+ Argument(other).swap(*this);
+ }
+ return *this;
+ }
+
+ void swap(Argument &other)
+ {
+ using std::swap;
+ swap(this->comp, other.comp);
+ swap(this->opt, other.opt);
+ swap(this->arg, other.arg);
+ }
+
+ bool isNull() const
+ {
+ return comp.expired() || !opt || !arg;
+ }
+
+ Option parent() const;
+
+ unsigned int numElements() const;
+
+ bool boolValue() const;
+ const char *stringValue(unsigned int index = 0) const;
+ int intValue(unsigned int index = 0) const;
+ unsigned int uintValue(unsigned int index = 0) const;
+
+ unsigned int numberOfTimesSet() const;
+ std::vector<const char *> stringValues() const;
+ std::vector<int> intValues() const;
+ std::vector<unsigned int> uintValues() const;
+
+ GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(!isNull())
+private:
+ weak_gpgme_conf_comp_t comp;
+ gpgme_conf_opt_t opt;
+ gpgme_conf_arg_t arg;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Level level);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Type type);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Flag flag);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Component &component);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Option &option);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Argument &argument);
+
+} // namespace Configuration
+} // namespace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Component)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Option)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Configuration::Argument)
+
+#endif // __GPGMEPP_CONFIGURATION_H__
diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp
new file mode 100644
index 0000000..00f397b
--- /dev/null
+++ b/lang/cpp/src/context.cpp
@@ -0,0 +1,1639 @@
+/*
+ context.cpp - wraps a gpgme key context
+ Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <context.h>
+#include <eventloopinteractor.h>
+#include <trustitem.h>
+#include <keylistresult.h>
+#include <keygenerationresult.h>
+#include <importresult.h>
+#include <decryptionresult.h>
+#include <verificationresult.h>
+#include <signingresult.h>
+#include <encryptionresult.h>
+#include <engineinfo.h>
+#include <editinteractor.h>
+#include <vfsmountresult.h>
+
+#include <interfaces/assuantransaction.h>
+#include <defaultassuantransaction.h>
+
+#include "callbacks.h"
+#include "data_p.h"
+#include "context_p.h"
+#include "util.h"
+#include "tofuinfo.h"
+
+#include <gpgme.h>
+
+#include <istream>
+#ifndef NDEBUG
+#include <iostream>
+using std::cerr;
+using std::endl;
+#endif
+
+#include <cassert>
+
+namespace GpgME
+{
+
+static inline unsigned int xtoi_1(const char *str)
+{
+ const unsigned int ch = *str;
+ const unsigned int result =
+ ch <= '9' ? ch - '0' :
+ ch <= 'F' ? ch - 'A' + 10 :
+ /* else */ ch - 'a' + 10 ;
+ return result < 16 ? result : 0 ;
+}
+static inline int xtoi_2(const char *str)
+{
+ return xtoi_1(str) * 16U + xtoi_1(str + 1);
+}
+
+static void percent_unescape(std::string &s, bool plus2space)
+{
+ std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
+ while (src != end) {
+ if (*src == '%' && end - src > 2) {
+ *dest++ = xtoi_2(&*++src);
+ src += 2;
+ } else if (*src == '+' && plus2space) {
+ *dest++ = ' ';
+ ++src;
+ } else {
+ *dest++ = *src++;
+ }
+ }
+ s.erase(dest, end);
+}
+
+void initializeLibrary()
+{
+ gpgme_check_version(0);
+}
+
+Error initializeLibrary(int)
+{
+ if (gpgme_check_version(GPGME_VERSION)) {
+ return Error();
+ } else {
+ return Error::fromCode(GPG_ERR_USER_1);
+ }
+}
+
+static void format_error(gpgme_error_t err, std::string &str)
+{
+ char buffer[ 1024 ];
+ gpgme_strerror_r(err, buffer, sizeof buffer);
+ buffer[ sizeof buffer - 1 ] = '\0';
+ str = buffer;
+}
+
+const char *Error::source() const
+{
+ return gpgme_strsource((gpgme_error_t)mErr);
+}
+
+const char *Error::asString() const
+{
+ if (mMessage.empty()) {
+ format_error(static_cast<gpgme_error_t>(mErr), mMessage);
+ }
+ return mMessage.c_str();
+}
+
+int Error::code() const
+{
+ return gpgme_err_code(mErr);
+}
+
+int Error::sourceID() const
+{
+ return gpgme_err_source(mErr);
+}
+
+bool Error::isCanceled() const
+{
+ return code() == GPG_ERR_CANCELED;
+}
+
+int Error::toErrno() const
+{
+//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
+ return gpgme_err_code_to_errno(static_cast<gpgme_err_code_t>(code()));
+//#else
+// return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
+//#endif
+}
+
+// static
+bool Error::hasSystemError()
+{
+ return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
+}
+
+// static
+void Error::setSystemError(gpg_err_code_t err)
+{
+ setErrno(gpgme_err_code_to_errno(err));
+}
+
+// static
+void Error::setErrno(int err)
+{
+ gpgme_err_set_errno(err);
+}
+
+// static
+Error Error::fromSystemError(unsigned int src)
+{
+ return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_syserror()));
+}
+
+// static
+Error Error::fromErrno(int err, unsigned int src)
+{
+ return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), gpgme_err_code_from_errno(err)));
+}
+
+// static
+Error Error::fromCode(unsigned int err, unsigned int src)
+{
+ return Error(gpgme_err_make(static_cast<gpgme_err_source_t>(src), static_cast<gpgme_err_code_t>(err)));
+}
+
+std::ostream &operator<<(std::ostream &os, const Error &err)
+{
+ return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
+}
+
+Context::Context(gpgme_ctx_t ctx) : d(new Private(ctx))
+{
+}
+
+Context::~Context()
+{
+ delete d;
+}
+
+Context *Context::createForProtocol(Protocol proto)
+{
+ gpgme_ctx_t ctx = 0;
+ if (gpgme_new(&ctx) != 0) {
+ return 0;
+ }
+
+ switch (proto) {
+ case OpenPGP:
+ if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP) != 0) {
+ gpgme_release(ctx);
+ return 0;
+ }
+ break;
+ case CMS:
+ if (gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS) != 0) {
+ gpgme_release(ctx);
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return new Context(ctx);
+}
+
+std::unique_ptr<Context> Context::createForEngine(Engine eng, Error *error)
+{
+ gpgme_ctx_t ctx = 0;
+ if (const gpgme_error_t err = gpgme_new(&ctx)) {
+ if (error) {
+ *error = Error(err);
+ }
+ return std::unique_ptr<Context>();
+ }
+
+ switch (eng) {
+ case AssuanEngine:
+ if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_ASSUAN)) {
+ gpgme_release(ctx);
+ if (error) {
+ *error = Error(err);
+ }
+ return std::unique_ptr<Context>();
+ }
+ break;
+ case G13Engine:
+ if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_G13)) {
+ gpgme_release(ctx);
+ if (error) {
+ *error = Error(err);
+ }
+ return std::unique_ptr<Context>();
+ }
+ break;
+ case SpawnEngine:
+ if (const gpgme_error_t err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_SPAWN)) {
+ gpgme_release(ctx);
+ if (error) {
+ *error = Error(err);
+ }
+ return std::unique_ptr<Context>();
+ }
+ break;
+ default:
+ if (error) {
+ *error = Error::fromCode(GPG_ERR_INV_ARG);
+ }
+ return std::unique_ptr<Context>();
+ }
+
+ if (error) {
+ *error = Error();
+ }
+
+ return std::unique_ptr<Context>(new Context(ctx));
+}
+
+//
+//
+// Context::Private
+//
+//
+
+Context::Private::Private(gpgme_ctx_t c)
+ : ctx(c),
+ iocbs(0),
+ lastop(None),
+ lasterr(GPG_ERR_NO_ERROR),
+ lastAssuanInquireData(Data::null),
+ lastAssuanTransaction(),
+ lastEditInteractor(),
+ lastCardEditInteractor()
+{
+
+}
+
+Context::Private::~Private()
+{
+ if (ctx) {
+ gpgme_release(ctx);
+ }
+ ctx = 0;
+ delete iocbs;
+}
+
+//
+//
+// Context attributes:
+//
+//
+
+Protocol Context::protocol() const
+{
+ gpgme_protocol_t p = gpgme_get_protocol(d->ctx);
+ switch (p) {
+ case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+ case GPGME_PROTOCOL_CMS: return CMS;
+ default: return UnknownProtocol;
+ }
+}
+
+void Context::setArmor(bool useArmor)
+{
+ gpgme_set_armor(d->ctx, int(useArmor));
+}
+bool Context::armor() const
+{
+ return gpgme_get_armor(d->ctx);
+}
+
+void Context::setTextMode(bool useTextMode)
+{
+ gpgme_set_textmode(d->ctx, int(useTextMode));
+}
+bool Context::textMode() const
+{
+ return gpgme_get_textmode(d->ctx);
+}
+
+void Context::setOffline(bool useOfflineMode)
+{
+ gpgme_set_offline(d->ctx, int(useOfflineMode));
+}
+bool Context::offline() const
+{
+ return gpgme_get_offline(d->ctx);
+}
+
+void Context::setIncludeCertificates(int which)
+{
+ if (which == DefaultCertificates) {
+ which = GPGME_INCLUDE_CERTS_DEFAULT;
+ }
+ gpgme_set_include_certs(d->ctx, which);
+}
+
+int Context::includeCertificates() const
+{
+ return gpgme_get_include_certs(d->ctx);
+}
+
+void Context::setKeyListMode(unsigned int mode)
+{
+ gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(0, mode));
+}
+
+void Context::addKeyListMode(unsigned int mode)
+{
+ const unsigned int cur = gpgme_get_keylist_mode(d->ctx);
+ gpgme_set_keylist_mode(d->ctx, add_to_gpgme_keylist_mode_t(cur, mode));
+}
+
+unsigned int Context::keyListMode() const
+{
+ return convert_from_gpgme_keylist_mode_t(gpgme_get_keylist_mode(d->ctx));
+}
+
+void Context::setProgressProvider(ProgressProvider *provider)
+{
+ gpgme_set_progress_cb(d->ctx, provider ? &progress_callback : 0, provider);
+}
+ProgressProvider *Context::progressProvider() const
+{
+ void *pp = 0;
+ gpgme_progress_cb_t pcb = &progress_callback;
+ gpgme_get_progress_cb(d->ctx, &pcb, &pp);
+ return static_cast<ProgressProvider *>(pp);
+}
+
+void Context::setPassphraseProvider(PassphraseProvider *provider)
+{
+ gpgme_set_passphrase_cb(d->ctx, provider ? &passphrase_callback : 0, provider);
+}
+
+PassphraseProvider *Context::passphraseProvider() const
+{
+ void *pp = 0;
+ gpgme_passphrase_cb_t pcb = &passphrase_callback;
+ gpgme_get_passphrase_cb(d->ctx, &pcb, &pp);
+ return static_cast<PassphraseProvider *>(pp);
+}
+
+void Context::setManagedByEventLoopInteractor(bool manage)
+{
+ if (!EventLoopInteractor::instance()) {
+#ifndef NDEBUG
+ cerr << "Context::setManagedByEventLoopInteractor(): "
+ "You must create an instance of EventLoopInteractor "
+ "before using anything that needs one." << endl;
+#endif
+ return;
+ }
+ if (manage) {
+ EventLoopInteractor::instance()->manage(this);
+ } else {
+ EventLoopInteractor::instance()->unmanage(this);
+ }
+}
+bool Context::managedByEventLoopInteractor() const
+{
+ return d->iocbs != 0;
+}
+
+void Context::installIOCallbacks(gpgme_io_cbs *iocbs)
+{
+ if (!iocbs) {
+ uninstallIOCallbacks();
+ return;
+ }
+ gpgme_set_io_cbs(d->ctx, iocbs);
+ delete d->iocbs; d->iocbs = iocbs;
+}
+
+void Context::uninstallIOCallbacks()
+{
+ static gpgme_io_cbs noiocbs = { 0, 0, 0, 0, 0 };
+ // io.add == 0 means disable io callbacks:
+ gpgme_set_io_cbs(d->ctx, &noiocbs);
+ delete d->iocbs; d->iocbs = 0;
+}
+
+Error Context::setLocale(int cat, const char *val)
+{
+ return Error(d->lasterr = gpgme_set_locale(d->ctx, cat, val));
+}
+
+EngineInfo Context::engineInfo() const
+{
+ return EngineInfo(gpgme_ctx_get_engine_info(d->ctx));
+}
+
+Error Context::setEngineFileName(const char *filename)
+{
+ const char *const home_dir = engineInfo().homeDirectory();
+ return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
+}
+
+Error Context::setEngineHomeDirectory(const char *home_dir)
+{
+ const char *const filename = engineInfo().fileName();
+ return Error(gpgme_ctx_set_engine_info(d->ctx, gpgme_get_protocol(d->ctx), filename, home_dir));
+}
+
+//
+//
+// Key Management
+//
+//
+
+Error Context::startKeyListing(const char *pattern, bool secretOnly)
+{
+ d->lastop = Private::KeyList;
+ return Error(d->lasterr = gpgme_op_keylist_start(d->ctx, pattern, int(secretOnly)));
+}
+
+Error Context::startKeyListing(const char *patterns[], bool secretOnly)
+{
+ d->lastop = Private::KeyList;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+ if (!patterns || !patterns[0] || !patterns[1]) {
+ // max. one pattern -> use the non-ext version
+ return startKeyListing(patterns ? patterns[0] : 0, secretOnly);
+ }
+#endif
+ return Error(d->lasterr = gpgme_op_keylist_ext_start(d->ctx, patterns, int(secretOnly), 0));
+}
+
+Key Context::nextKey(GpgME::Error &e)
+{
+ d->lastop = Private::KeyList;
+ gpgme_key_t key;
+ e = Error(d->lasterr = gpgme_op_keylist_next(d->ctx, &key));
+ return Key(key, false);
+}
+
+KeyListResult Context::endKeyListing()
+{
+ d->lasterr = gpgme_op_keylist_end(d->ctx);
+ return keyListResult();
+}
+
+KeyListResult Context::keyListResult() const
+{
+ return KeyListResult(d->ctx, Error(d->lasterr));
+}
+
+Key Context::key(const char *fingerprint, GpgME::Error &e , bool secret /*, bool forceUpdate*/)
+{
+ d->lastop = Private::KeyList;
+ gpgme_key_t key;
+ e = Error(d->lasterr = gpgme_get_key(d->ctx, fingerprint, &key, int(secret)/*, int( forceUpdate )*/));
+ return Key(key, false);
+}
+
+KeyGenerationResult Context::generateKey(const char *parameters, Data &pubKey)
+{
+ d->lastop = Private::KeyGen;
+ Data::Private *const dp = pubKey.impl();
+ d->lasterr = gpgme_op_genkey(d->ctx, parameters, dp ? dp->data : 0, 0);
+ return KeyGenerationResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startKeyGeneration(const char *parameters, Data &pubKey)
+{
+ d->lastop = Private::KeyGen;
+ Data::Private *const dp = pubKey.impl();
+ return Error(d->lasterr = gpgme_op_genkey_start(d->ctx, parameters, dp ? dp->data : 0, 0));
+}
+
+KeyGenerationResult Context::keyGenerationResult() const
+{
+ if (d->lastop & Private::KeyGen) {
+ return KeyGenerationResult(d->ctx, Error(d->lasterr));
+ } else {
+ return KeyGenerationResult();
+ }
+}
+
+Error Context::exportPublicKeys(const char *pattern, Data &keyData)
+{
+ d->lastop = Private::Export;
+ Data::Private *const dp = keyData.impl();
+ return Error(d->lasterr = gpgme_op_export(d->ctx, pattern, 0, dp ? dp->data : 0));
+}
+
+Error Context::exportPublicKeys(const char *patterns[], Data &keyData)
+{
+ d->lastop = Private::Export;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+ if (!patterns || !patterns[0] || !patterns[1]) {
+ // max. one pattern -> use the non-ext version
+ return exportPublicKeys(patterns ? patterns[0] : 0, keyData);
+ }
+#endif
+ Data::Private *const dp = keyData.impl();
+ return Error(d->lasterr = gpgme_op_export_ext(d->ctx, patterns, 0, dp ? dp->data : 0));
+}
+
+Error Context::startPublicKeyExport(const char *pattern, Data &keyData)
+{
+ d->lastop = Private::Export;
+ Data::Private *const dp = keyData.impl();
+ return Error(d->lasterr = gpgme_op_export_start(d->ctx, pattern, 0, dp ? dp->data : 0));
+}
+
+Error Context::startPublicKeyExport(const char *patterns[], Data &keyData)
+{
+ d->lastop = Private::Export;
+#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
+ if (!patterns || !patterns[0] || !patterns[1]) {
+ // max. one pattern -> use the non-ext version
+ return startPublicKeyExport(patterns ? patterns[0] : 0, keyData);
+ }
+#endif
+ Data::Private *const dp = keyData.impl();
+ return Error(d->lasterr = gpgme_op_export_ext_start(d->ctx, patterns, 0, dp ? dp->data : 0));
+}
+
+ImportResult Context::importKeys(const Data &data)
+{
+ d->lastop = Private::Import;
+ const Data::Private *const dp = data.impl();
+ d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
+ return ImportResult(d->ctx, Error(d->lasterr));
+}
+
+ImportResult Context::importKeys(const std::vector<Key> &kk)
+{
+ d->lastop = Private::Import;
+ d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED);
+
+ bool shouldHaveResult = false;
+ gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
+ gpgme_key_t *keys_it = &keys[0];
+ for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+ if (it->impl()) {
+ *keys_it++ = it->impl();
+ }
+ }
+ *keys_it++ = 0;
+ d->lasterr = gpgme_op_import_keys(d->ctx, keys);
+ shouldHaveResult = true;
+ if ((gpgme_err_code(d->lasterr) == GPG_ERR_NOT_IMPLEMENTED ||
+ gpgme_err_code(d->lasterr) == GPG_ERR_NOT_SUPPORTED) &&
+ protocol() == CMS) {
+ // ok, try the workaround (export+import):
+ std::vector<const char *> fprs;
+ for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+ if (const char *fpr = it->primaryFingerprint()) {
+ if (*fpr) {
+ fprs.push_back(fpr);
+ }
+ } else if (const char *keyid = it->keyID()) {
+ if (*keyid) {
+ fprs.push_back(keyid);
+ }
+ }
+ }
+ fprs.push_back(0);
+ Data data;
+ Data::Private *const dp = data.impl();
+ const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode(d->ctx);
+ gpgme_set_keylist_mode(d->ctx, GPGME_KEYLIST_MODE_EXTERN);
+ d->lasterr = gpgme_op_export_ext(d->ctx, &fprs[0], 0, dp ? dp->data : 0);
+ gpgme_set_keylist_mode(d->ctx, oldMode);
+ if (!d->lasterr) {
+ data.seek(0, SEEK_SET);
+ d->lasterr = gpgme_op_import(d->ctx, dp ? dp->data : 0);
+ shouldHaveResult = true;
+ }
+ }
+ delete[] keys;
+ if (shouldHaveResult) {
+ return ImportResult(d->ctx, Error(d->lasterr));
+ } else {
+ return ImportResult(Error(d->lasterr));
+ }
+}
+
+Error Context::startKeyImport(const Data &data)
+{
+ d->lastop = Private::Import;
+ const Data::Private *const dp = data.impl();
+ return Error(d->lasterr = gpgme_op_import_start(d->ctx, dp ? dp->data : 0));
+}
+
+Error Context::startKeyImport(const std::vector<Key> &kk)
+{
+ d->lastop = Private::Import;
+ gpgme_key_t * const keys = new gpgme_key_t[ kk.size() + 1 ];
+ gpgme_key_t *keys_it = &keys[0];
+ for (std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it) {
+ if (it->impl()) {
+ *keys_it++ = it->impl();
+ }
+ }
+ *keys_it++ = 0;
+ Error err = Error(d->lasterr = gpgme_op_import_keys_start(d->ctx, keys));
+ delete[] keys;
+ return err;
+}
+
+ImportResult Context::importResult() const
+{
+ if (d->lastop & Private::Import) {
+ return ImportResult(d->ctx, Error(d->lasterr));
+ } else {
+ return ImportResult();
+ }
+}
+
+Error Context::deleteKey(const Key &key, bool allowSecretKeyDeletion)
+{
+ d->lastop = Private::Delete;
+ return Error(d->lasterr = gpgme_op_delete(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
+}
+
+Error Context::startKeyDeletion(const Key &key, bool allowSecretKeyDeletion)
+{
+ d->lastop = Private::Delete;
+ return Error(d->lasterr = gpgme_op_delete_start(d->ctx, key.impl(), int(allowSecretKeyDeletion)));
+}
+
+Error Context::passwd(const Key &key)
+{
+ d->lastop = Private::Passwd;
+ return Error(d->lasterr = gpgme_op_passwd(d->ctx, key.impl(), 0U));
+}
+
+Error Context::startPasswd(const Key &key)
+{
+ d->lastop = Private::Passwd;
+ return Error(d->lasterr = gpgme_op_passwd_start(d->ctx, key.impl(), 0U));
+}
+
+
+#pragma GCC push_diagnostics
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+Error Context::edit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
+{
+ d->lastop = Private::Edit;
+ d->lastEditInteractor = std::move(func);
+ Data::Private *const dp = data.impl();
+ return Error(d->lasterr = gpgme_op_edit(d->ctx, key.impl(),
+ d->lastEditInteractor.get() ? edit_interactor_callback : 0,
+ d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
+ dp ? dp->data : 0));
+}
+
+
+Error Context::startEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
+{
+ d->lastop = Private::Edit;
+ d->lastEditInteractor = std::move(func);
+ Data::Private *const dp = data.impl();
+ return Error(d->lasterr = gpgme_op_edit_start(d->ctx, key.impl(),
+ d->lastEditInteractor.get() ? edit_interactor_callback : 0,
+ d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
+ dp ? dp->data : 0));
+}
+
+
+EditInteractor *Context::lastEditInteractor() const
+{
+ return d->lastEditInteractor.get();
+}
+
+std::unique_ptr<EditInteractor> Context::takeLastEditInteractor()
+{
+ return std::move(d->lastEditInteractor);
+}
+
+
+Error Context::cardEdit(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
+{
+ d->lastop = Private::CardEdit;
+ d->lastCardEditInteractor = std::move(func);
+ Data::Private *const dp = data.impl();
+ return Error(d->lasterr = gpgme_op_card_edit(d->ctx, key.impl(),
+ d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
+ d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
+ dp ? dp->data : 0));
+}
+
+Error Context::startCardEditing(const Key &key, std::unique_ptr<EditInteractor> func, Data &data)
+{
+ d->lastop = Private::CardEdit;
+ d->lastCardEditInteractor = std::move(func);
+ Data::Private *const dp = data.impl();
+ return Error(d->lasterr = gpgme_op_card_edit_start(d->ctx, key.impl(),
+ d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
+ d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
+ dp ? dp->data : 0));
+}
+
+#pragma GCC pop_diagnostics
+
+EditInteractor *Context::lastCardEditInteractor() const
+{
+ return d->lastCardEditInteractor.get();
+}
+
+std::unique_ptr<EditInteractor> Context::takeLastCardEditInteractor()
+{
+ return std::move(d->lastCardEditInteractor);
+}
+
+Error Context::startTrustItemListing(const char *pattern, int maxLevel)
+{
+ d->lastop = Private::TrustList;
+ return Error(d->lasterr = gpgme_op_trustlist_start(d->ctx, pattern, maxLevel));
+}
+
+TrustItem Context::nextTrustItem(Error &e)
+{
+ gpgme_trust_item_t ti = 0;
+ e = Error(d->lasterr = gpgme_op_trustlist_next(d->ctx, &ti));
+ return TrustItem(ti);
+}
+
+Error Context::endTrustItemListing()
+{
+ return Error(d->lasterr = gpgme_op_trustlist_end(d->ctx));
+}
+
+static gpgme_error_t assuan_transaction_data_callback(void *opaque, const void *data, size_t datalen)
+{
+ assert(opaque);
+ AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
+ return t->data(static_cast<const char *>(data), datalen).encodedError();
+}
+
+static gpgme_error_t assuan_transaction_inquire_callback(void *opaque, const char *name, const char *args, gpgme_data_t *r_data)
+{
+ assert(opaque);
+ Context::Private *p = static_cast<Context::Private *>(opaque);
+ AssuanTransaction *t = p->lastAssuanTransaction.get();
+ assert(t);
+ Error err;
+ if (name) {
+ p->lastAssuanInquireData = t->inquire(name, args, err);
+ } else {
+ p->lastAssuanInquireData = Data::null;
+ }
+ if (!p->lastAssuanInquireData.isNull()) {
+ *r_data = p->lastAssuanInquireData.impl()->data;
+ }
+ return err.encodedError();
+}
+
+static gpgme_error_t assuan_transaction_status_callback(void *opaque, const char *status, const char *args)
+{
+ assert(opaque);
+ AssuanTransaction *t = static_cast<AssuanTransaction *>(opaque);
+ std::string a = args;
+ percent_unescape(a, true); // ### why doesn't gpgme do this??
+ return t->status(status, a.c_str()).encodedError();
+}
+
+Error Context::assuanTransact(const char *command)
+{
+ return assuanTransact(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
+}
+
+Error Context::assuanTransact(const char *command, std::unique_ptr<AssuanTransaction> transaction)
+{
+ gpgme_error_t err, operr;
+
+ d->lastop = Private::AssuanTransact;
+ d->lastAssuanTransaction = std::move(transaction);
+ if (!d->lastAssuanTransaction.get()) {
+ return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
+ }
+ err = gpgme_op_assuan_transact_ext
+ (d->ctx,
+ command,
+ assuan_transaction_data_callback,
+ d->lastAssuanTransaction.get(),
+ assuan_transaction_inquire_callback,
+ d,
+ assuan_transaction_status_callback,
+ d->lastAssuanTransaction.get(),
+ &operr);
+
+ if (!err)
+ err = operr;
+ d->lasterr = err;
+
+ return Error(d->lasterr);
+}
+
+Error Context::startAssuanTransaction(const char *command)
+{
+ return startAssuanTransaction(command, std::unique_ptr<AssuanTransaction>(new DefaultAssuanTransaction));
+}
+
+Error Context::startAssuanTransaction(const char *command, std::unique_ptr<AssuanTransaction> transaction)
+{
+ gpgme_error_t err;
+
+ d->lastop = Private::AssuanTransact;
+ d->lastAssuanTransaction = std::move(transaction);
+ if (!d->lastAssuanTransaction.get()) {
+ return Error(d->lasterr = make_error(GPG_ERR_INV_ARG));
+ }
+ err = gpgme_op_assuan_transact_start
+ (d->ctx,
+ command,
+ assuan_transaction_data_callback,
+ d->lastAssuanTransaction.get(),
+ assuan_transaction_inquire_callback,
+ d,
+ assuan_transaction_status_callback,
+ d->lastAssuanTransaction.get());
+
+ d->lasterr = err;
+
+ return Error(d->lasterr);
+}
+
+AssuanTransaction *Context::lastAssuanTransaction() const
+{
+ return d->lastAssuanTransaction.get();
+}
+
+std::unique_ptr<AssuanTransaction> Context::takeLastAssuanTransaction()
+{
+ return std::move(d->lastAssuanTransaction);
+}
+
+DecryptionResult Context::decrypt(const Data &cipherText, Data &plainText)
+{
+ d->lastop = Private::Decrypt;
+ const Data::Private *const cdp = cipherText.impl();
+ Data::Private *const pdp = plainText.impl();
+ d->lasterr = gpgme_op_decrypt(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
+ return DecryptionResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startDecryption(const Data &cipherText, Data &plainText)
+{
+ d->lastop = Private::Decrypt;
+ const Data::Private *const cdp = cipherText.impl();
+ Data::Private *const pdp = plainText.impl();
+ return Error(d->lasterr = gpgme_op_decrypt_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
+}
+
+DecryptionResult Context::decryptionResult() const
+{
+ if (d->lastop & Private::Decrypt) {
+ return DecryptionResult(d->ctx, Error(d->lasterr));
+ } else {
+ return DecryptionResult();
+ }
+}
+
+VerificationResult Context::verifyDetachedSignature(const Data &signature, const Data &signedText)
+{
+ d->lastop = Private::Verify;
+ const Data::Private *const sdp = signature.impl();
+ const Data::Private *const tdp = signedText.impl();
+ d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0);
+ return VerificationResult(d->ctx, Error(d->lasterr));
+}
+
+VerificationResult Context::verifyOpaqueSignature(const Data &signedData, Data &plainText)
+{
+ d->lastop = Private::Verify;
+ const Data::Private *const sdp = signedData.impl();
+ Data::Private *const pdp = plainText.impl();
+ d->lasterr = gpgme_op_verify(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0);
+ return VerificationResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startDetachedSignatureVerification(const Data &signature, const Data &signedText)
+{
+ d->lastop = Private::Verify;
+ const Data::Private *const sdp = signature.impl();
+ const Data::Private *const tdp = signedText.impl();
+ return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0));
+}
+
+Error Context::startOpaqueSignatureVerification(const Data &signedData, Data &plainText)
+{
+ d->lastop = Private::Verify;
+ const Data::Private *const sdp = signedData.impl();
+ Data::Private *const pdp = plainText.impl();
+ return Error(d->lasterr = gpgme_op_verify_start(d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0));
+}
+
+VerificationResult Context::verificationResult() const
+{
+ if (d->lastop & Private::Verify) {
+ return VerificationResult(d->ctx, Error(d->lasterr));
+ } else {
+ return VerificationResult();
+ }
+}
+
+std::pair<DecryptionResult, VerificationResult> Context::decryptAndVerify(const Data &cipherText, Data &plainText)
+{
+ d->lastop = Private::DecryptAndVerify;
+ const Data::Private *const cdp = cipherText.impl();
+ Data::Private *const pdp = plainText.impl();
+ d->lasterr = gpgme_op_decrypt_verify(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0);
+ return std::make_pair(DecryptionResult(d->ctx, Error(d->lasterr)),
+ VerificationResult(d->ctx, Error(d->lasterr)));
+}
+
+Error Context::startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText)
+{
+ d->lastop = Private::DecryptAndVerify;
+ const Data::Private *const cdp = cipherText.impl();
+ Data::Private *const pdp = plainText.impl();
+ return Error(d->lasterr = gpgme_op_decrypt_verify_start(d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0));
+}
+
+unsigned int to_auditlog_flags(unsigned int flags)
+{
+ unsigned int result = 0;
+ if (flags & Context::HtmlAuditLog) {
+ result |= GPGME_AUDITLOG_HTML;
+ }
+ if (flags & Context::AuditLogWithHelp) {
+ result |= GPGME_AUDITLOG_WITH_HELP;
+ }
+ return result;
+}
+
+Error Context::startGetAuditLog(Data &output, unsigned int flags)
+{
+ d->lastop = Private::GetAuditLog;
+ Data::Private *const odp = output.impl();
+ return Error(d->lasterr = gpgme_op_getauditlog_start(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
+}
+
+Error Context::getAuditLog(Data &output, unsigned int flags)
+{
+ d->lastop = Private::GetAuditLog;
+ Data::Private *const odp = output.impl();
+ return Error(d->lasterr = gpgme_op_getauditlog(d->ctx, odp ? odp->data : 0, to_auditlog_flags(flags)));
+}
+
+void Context::clearSigningKeys()
+{
+ gpgme_signers_clear(d->ctx);
+}
+
+Error Context::addSigningKey(const Key &key)
+{
+ return Error(d->lasterr = gpgme_signers_add(d->ctx, key.impl()));
+}
+
+Key Context::signingKey(unsigned int idx) const
+{
+ gpgme_key_t key = gpgme_signers_enum(d->ctx, idx);
+ return Key(key, false);
+}
+
+std::vector<Key> Context::signingKeys() const
+{
+ std::vector<Key> result;
+ gpgme_key_t key;
+ for (unsigned int i = 0 ; (key = gpgme_signers_enum(d->ctx, i)) ; ++i) {
+ result.push_back(Key(key, false));
+ }
+ return result;
+}
+
+void Context::clearSignatureNotations()
+{
+ gpgme_sig_notation_clear(d->ctx);
+}
+
+GpgME::Error Context::addSignatureNotation(const char *name, const char *value, unsigned int flags)
+{
+ return Error(gpgme_sig_notation_add(d->ctx, name, value, add_to_gpgme_sig_notation_flags_t(0, flags)));
+}
+
+GpgME::Error Context::addSignaturePolicyURL(const char *url, bool critical)
+{
+ return Error(gpgme_sig_notation_add(d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0));
+}
+
+const char *Context::signaturePolicyURL() const
+{
+ for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+ if (!n->name) {
+ return n->value;
+ }
+ }
+}
+
+Notation Context::signatureNotation(unsigned int idx) const
+{
+ for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+ if (n->name) {
+ if (idx-- == 0) {
+ return Notation(n);
+ }
+ }
+ }
+ return Notation();
+}
+
+std::vector<Notation> Context::signatureNotations() const
+{
+ std::vector<Notation> result;
+ for (gpgme_sig_notation_t n = gpgme_sig_notation_get(d->ctx) ; n ; n = n->next) {
+ if (n->name) {
+ result.push_back(Notation(n));
+ }
+ }
+ return result;
+}
+
+static gpgme_sig_mode_t sigmode2sigmode(SignatureMode mode)
+{
+ switch (mode) {
+ default:
+ case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
+ case Detached: return GPGME_SIG_MODE_DETACH;
+ case Clearsigned: return GPGME_SIG_MODE_CLEAR;
+ }
+}
+
+SigningResult Context::sign(const Data &plainText, Data &signature, SignatureMode mode)
+{
+ d->lastop = Private::Sign;
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const sdp = signature.impl();
+ d->lasterr = gpgme_op_sign(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode));
+ return SigningResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::startSigning(const Data &plainText, Data &signature, SignatureMode mode)
+{
+ d->lastop = Private::Sign;
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const sdp = signature.impl();
+ return Error(d->lasterr = gpgme_op_sign_start(d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode(mode)));
+}
+
+SigningResult Context::signingResult() const
+{
+ if (d->lastop & Private::Sign) {
+ return SigningResult(d->ctx, Error(d->lasterr));
+ } else {
+ return SigningResult();
+ }
+}
+
+static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags flags)
+{
+ unsigned int result = 0;
+ if (flags & Context::AlwaysTrust) {
+ result |= GPGME_ENCRYPT_ALWAYS_TRUST;
+ }
+ if (flags & Context::NoEncryptTo) {
+ result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
+ }
+ if (flags & Context::Prepare) {
+ result |= GPGME_ENCRYPT_PREPARE;
+ }
+ if (flags & Context::ExpectSign) {
+ result |= GPGME_ENCRYPT_EXPECT_SIGN;
+ }
+ if (flags & Context::NoCompress) {
+ result |= GPGME_ENCRYPT_NO_COMPRESS;
+ }
+ if (flags & Context::Symmetric) {
+ result |= GPGME_ENCRYPT_SYMMETRIC;
+ }
+ return static_cast<gpgme_encrypt_flags_t>(result);
+}
+
+gpgme_key_t *Context::getKeysFromRecipients(const std::vector<Key> &recipients)
+{
+ if (recipients.empty()) {
+ return nullptr;
+ }
+ gpgme_key_t *ret = new gpgme_key_t[ recipients.size() + 1 ];
+ gpgme_key_t *keys_it = ret;
+ for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+ if (it->impl()) {
+ *keys_it++ = it->impl();
+ }
+ }
+ *keys_it++ = 0;
+ return ret;
+}
+
+EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+ d->lastop = Private::Encrypt;
+ if (flags & NoEncryptTo) {
+ return EncryptionResult(Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED)));
+ }
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const cdp = cipherText.impl();
+ gpgme_key_t *const keys = getKeysFromRecipients(recipients);
+ d->lasterr = gpgme_op_encrypt(d->ctx, keys, encryptflags2encryptflags(flags),
+ pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+ if (keys) {
+ delete[] keys;
+ }
+ return EncryptionResult(d->ctx, Error(d->lasterr));
+}
+
+Error Context::encryptSymmetrically(const Data &plainText, Data &cipherText)
+{
+ d->lastop = Private::Encrypt;
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const cdp = cipherText.impl();
+ return Error(d->lasterr = gpgme_op_encrypt(d->ctx, 0, (gpgme_encrypt_flags_t)0,
+ pdp ? pdp->data : 0, cdp ? cdp->data : 0));
+}
+
+Error Context::startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+ d->lastop = Private::Encrypt;
+ if (flags & NoEncryptTo) {
+ return Error(d->lasterr = make_error(GPG_ERR_NOT_IMPLEMENTED));
+ }
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const cdp = cipherText.impl();
+ gpgme_key_t *const keys = getKeysFromRecipients(recipients);
+ d->lasterr = gpgme_op_encrypt_start(d->ctx, keys, encryptflags2encryptflags(flags),
+ pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+ if (keys) {
+ delete[] keys;
+ }
+ return Error(d->lasterr);
+}
+
+EncryptionResult Context::encryptionResult() const
+{
+ if (d->lastop & Private::Encrypt) {
+ return EncryptionResult(d->ctx, Error(d->lasterr));
+ } else {
+ return EncryptionResult();
+ }
+}
+
+std::pair<SigningResult, EncryptionResult> Context::signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+ d->lastop = Private::SignAndEncrypt;
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const cdp = cipherText.impl();
+ gpgme_key_t *const keys = getKeysFromRecipients(recipients);
+ d->lasterr = gpgme_op_encrypt_sign(d->ctx, keys, encryptflags2encryptflags(flags),
+ pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+ if (keys) {
+ delete[] keys;
+ }
+ return std::make_pair(SigningResult(d->ctx, Error(d->lasterr)),
+ EncryptionResult(d->ctx, Error(d->lasterr)));
+}
+
+Error Context::startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags)
+{
+ d->lastop = Private::SignAndEncrypt;
+ const Data::Private *const pdp = plainText.impl();
+ Data::Private *const cdp = cipherText.impl();
+ gpgme_key_t *const keys = getKeysFromRecipients(recipients);
+ d->lasterr = gpgme_op_encrypt_sign_start(d->ctx, keys, encryptflags2encryptflags(flags),
+ pdp ? pdp->data : 0, cdp ? cdp->data : 0);
+ if (keys) {
+ delete[] keys;
+ }
+ return Error(d->lasterr);
+}
+
+Error Context::createVFS(const char *containerFile, const std::vector< Key > &recipients)
+{
+ d->lastop = Private::CreateVFS;
+ gpgme_key_t *const keys = new gpgme_key_t[ recipients.size() + 1 ];
+ gpgme_key_t *keys_it = keys;
+ for (std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it) {
+ if (it->impl()) {
+ *keys_it++ = it->impl();
+ }
+ }
+ *keys_it++ = 0;
+
+ gpgme_error_t op_err;
+ d->lasterr = gpgme_op_vfs_create(d->ctx, keys, containerFile, 0, &op_err);
+ delete[] keys;
+ Error error(d->lasterr);
+ if (error) {
+ return error;
+ }
+ return Error(d->lasterr = op_err);
+}
+
+VfsMountResult Context::mountVFS(const char *containerFile, const char *mountDir)
+{
+ d->lastop = Private::MountVFS;
+ gpgme_error_t op_err;
+ d->lasterr = gpgme_op_vfs_mount(d->ctx, containerFile, mountDir, 0, &op_err);
+ return VfsMountResult(d->ctx, Error(d->lasterr), Error(op_err));
+}
+
+Error Context::cancelPendingOperation()
+{
+ return Error(gpgme_cancel_async(d->ctx));
+}
+
+bool Context::poll()
+{
+ gpgme_error_t e = GPG_ERR_NO_ERROR;
+ const bool finished = gpgme_wait(d->ctx, &e, 0);
+ if (finished) {
+ d->lasterr = e;
+ }
+ return finished;
+}
+
+Error Context::wait()
+{
+ gpgme_error_t e = GPG_ERR_NO_ERROR;
+ gpgme_wait(d->ctx, &e, 1);
+ return Error(d->lasterr = e);
+}
+
+Error Context::lastError() const
+{
+ return Error(d->lasterr);
+}
+
+Context::PinentryMode Context::pinentryMode() const
+{
+ switch (gpgme_get_pinentry_mode (d->ctx)) {
+ case GPGME_PINENTRY_MODE_ASK:
+ return PinentryAsk;
+ case GPGME_PINENTRY_MODE_CANCEL:
+ return PinentryCancel;
+ case GPGME_PINENTRY_MODE_ERROR:
+ return PinentryError;
+ case GPGME_PINENTRY_MODE_LOOPBACK:
+ return PinentryLoopback;
+ case GPGME_PINENTRY_MODE_DEFAULT:
+ default:
+ return PinentryDefault;
+ }
+}
+
+Error Context::setPinentryMode(PinentryMode which)
+{
+ gpgme_pinentry_mode_t mode;
+ switch (which) {
+ case PinentryAsk:
+ mode = GPGME_PINENTRY_MODE_ASK;
+ break;
+ case PinentryCancel:
+ mode = GPGME_PINENTRY_MODE_CANCEL;
+ break;
+ case PinentryError:
+ mode = GPGME_PINENTRY_MODE_ERROR;
+ break;
+ case PinentryLoopback:
+ mode = GPGME_PINENTRY_MODE_LOOPBACK;
+ break;
+ case PinentryDefault:
+ default:
+ mode = GPGME_PINENTRY_MODE_DEFAULT;
+ }
+ return Error(d->lasterr = gpgme_set_pinentry_mode(d->ctx, mode));
+}
+
+static gpgme_tofu_policy_t to_tofu_policy_t(unsigned int policy)
+{
+ switch (policy) {
+ case TofuInfo::PolicyNone:
+ return GPGME_TOFU_POLICY_NONE;
+ case TofuInfo::PolicyAuto:
+ return GPGME_TOFU_POLICY_AUTO;
+ case TofuInfo::PolicyGood:
+ return GPGME_TOFU_POLICY_GOOD;
+ case TofuInfo::PolicyBad:
+ return GPGME_TOFU_POLICY_BAD;
+ case TofuInfo::PolicyAsk:
+ return GPGME_TOFU_POLICY_ASK;
+ case TofuInfo::PolicyUnknown:
+ return GPGME_TOFU_POLICY_UNKNOWN;
+ }
+}
+
+Error Context::setTofuPolicy(const Key &k, unsigned int policy)
+{
+ return Error(d->lasterr = gpgme_op_tofu_policy(d->ctx,
+ k.impl(), to_tofu_policy_t(policy)));
+}
+
+Error Context::setTofuPolicyStart(const Key &k, unsigned int policy)
+{
+ return Error(d->lasterr = gpgme_op_tofu_policy_start(d->ctx,
+ k.impl(), to_tofu_policy_t(policy)));
+}
+
+// Engine Spawn stuff
+Error Context::spawn(const char *file, const char *argv[],
+ Data &input, Data &output, Data &err,
+ SpawnFlags flags)
+{
+ return Error(d->lasterr = gpgme_op_spawn (d->ctx, file, argv,
+ input.impl() ? input.impl()->data : nullptr,
+ output.impl() ? output.impl()->data : nullptr,
+ err.impl() ? err.impl()->data : nullptr,
+ static_cast<int>(flags)));
+}
+
+Error Context::spawnAsync(const char *file, const char *argv[],
+ Data &input, Data &output, Data &err,
+ SpawnFlags flags)
+{
+ return Error(d->lasterr = gpgme_op_spawn_start (d->ctx, file, argv,
+ input.impl() ? input.impl()->data : nullptr,
+ output.impl() ? output.impl()->data : nullptr,
+ err.impl() ? err.impl()->data : nullptr,
+ static_cast<int>(flags)));
+}
+
+std::ostream &operator<<(std::ostream &os, Protocol proto)
+{
+ os << "GpgME::Protocol(";
+ switch (proto) {
+ case OpenPGP:
+ os << "OpenPGP";
+ break;
+ case CMS:
+ os << "CMS";
+ break;
+ default:
+ case UnknownProtocol:
+ os << "UnknownProtocol";
+ break;
+ }
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Engine eng)
+{
+ os << "GpgME::Engine(";
+ switch (eng) {
+ case GpgEngine:
+ os << "GpgEngine";
+ break;
+ case GpgSMEngine:
+ os << "GpgSMEngine";
+ break;
+ case GpgConfEngine:
+ os << "GpgConfEngine";
+ break;
+ case AssuanEngine:
+ os << "AssuanEngine";
+ break;
+ case SpawnEngine:
+ os << "SpawnEngine";
+ break;
+ default:
+ case UnknownEngine:
+ os << "UnknownEngine";
+ break;
+ }
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl)
+{
+ os << "GpgME::Context::CertificateInclusion(" << static_cast<int>(incl);
+ switch (incl) {
+ case Context::DefaultCertificates:
+ os << "(DefaultCertificates)";
+ break;
+ case Context::AllCertificatesExceptRoot:
+ os << "(AllCertificatesExceptRoot)";
+ break;
+ case Context::AllCertificates:
+ os << "(AllCertificates)";
+ break;
+ case Context::NoCertificates:
+ os << "(NoCertificates)";
+ break;
+ case Context::OnlySenderCertificate:
+ os << "(OnlySenderCertificate)";
+ break;
+ }
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, KeyListMode mode)
+{
+ os << "GpgME::KeyListMode(";
+#define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
+ CHECK(Local);
+ CHECK(Extern);
+ CHECK(Signatures);
+ CHECK(Validate);
+ CHECK(Ephemeral);
+ CHECK(WithTofu);
+#undef CHECK
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, SignatureMode mode)
+{
+ os << "GpgME::SignatureMode(";
+ switch (mode) {
+#define CHECK( x ) case x: os << #x; break
+ CHECK(NormalSignatureMode);
+ CHECK(Detached);
+ CHECK(Clearsigned);
+#undef CHECK
+ default:
+ os << "???" "(" << static_cast<int>(mode) << ')';
+ break;
+ }
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
+{
+ os << "GpgME::Context::EncryptionFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+ CHECK(AlwaysTrust);
+ CHECK(NoEncryptTo);
+ CHECK(Prepare);
+ CHECK(ExpectSign);
+ CHECK(NoCompress);
+ CHECK(Symmetric);
+#undef CHECK
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags)
+{
+ os << "GpgME::Context::AuditLogFlags(";
+#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
+ CHECK(HtmlAuditLog);
+ CHECK(AuditLogWithHelp);
+#undef CHECK
+ return os << ')';
+}
+
+} // namespace GpgME
+
+GpgME::Error GpgME::setDefaultLocale(int cat, const char *val)
+{
+ return Error(gpgme_set_locale(0, cat, val));
+}
+
+GpgME::EngineInfo GpgME::engineInfo(GpgME::Protocol proto)
+{
+ gpgme_engine_info_t ei = 0;
+ if (gpgme_get_engine_info(&ei)) {
+ return EngineInfo();
+ }
+
+ const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
+
+ for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
+ if (i->protocol == p) {
+ return EngineInfo(i);
+ }
+ }
+
+ return EngineInfo();
+}
+
+const char *GpgME::dirInfo(const char *what)
+{
+ return gpgme_get_dirinfo(what);
+}
+
+GpgME::Error GpgME::checkEngine(GpgME::Protocol proto)
+{
+ const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
+
+ return Error(gpgme_engine_check_version(p));
+}
+
+static const gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>(255);
+
+static gpgme_protocol_t engine2protocol(const GpgME::Engine engine)
+{
+ switch (engine) {
+ case GpgME::GpgEngine: return GPGME_PROTOCOL_OpenPGP;
+ case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
+ case GpgME::GpgConfEngine:
+ return GPGME_PROTOCOL_GPGCONF;
+ case GpgME::AssuanEngine:
+ return GPGME_PROTOCOL_ASSUAN;
+ case GpgME::G13Engine:
+ return GPGME_PROTOCOL_G13;
+ case GpgME::SpawnEngine:
+ return GPGME_PROTOCOL_SPAWN;
+ case GpgME::UnknownEngine:
+ ;
+ }
+ return UNKNOWN_PROTOCOL;
+}
+
+GpgME::EngineInfo GpgME::engineInfo(GpgME::Engine engine)
+{
+ gpgme_engine_info_t ei = 0;
+ if (gpgme_get_engine_info(&ei)) {
+ return EngineInfo();
+ }
+
+ const gpgme_protocol_t p = engine2protocol(engine);
+
+ for (gpgme_engine_info_t i = ei ; i ; i = i->next) {
+ if (i->protocol == p) {
+ return EngineInfo(i);
+ }
+ }
+
+ return EngineInfo();
+}
+
+GpgME::Error GpgME::checkEngine(GpgME::Engine engine)
+{
+ const gpgme_protocol_t p = engine2protocol(engine);
+
+ return Error(gpgme_engine_check_version(p));
+}
+
+static const unsigned long supported_features = 0
+ | GpgME::ValidatingKeylistModeFeature
+ | GpgME::CancelOperationFeature
+ | GpgME::WrongKeyUsageFeature
+ | GpgME::DefaultCertificateInclusionFeature
+ | GpgME::GetSetEngineInfoFeature
+ | GpgME::ClearAddGetSignatureNotationsFeature
+ | GpgME::SetDataFileNameFeeature
+ | GpgME::SignatureNotationsKeylistModeFeature
+ | GpgME::KeySignatureNotationsFeature
+ | GpgME::KeyIsQualifiedFeature
+ | GpgME::SignatureNotationsCriticalFlagFeature
+ | GpgME::SignatureNotationsFlagsFeature
+ | GpgME::SignatureNotationsHumanReadableFlagFeature
+ | GpgME::SubkeyIsQualifiedFeature
+ | GpgME::EngineInfoHomeDirFeature
+ | GpgME::DecryptionResultFileNameFeature
+ | GpgME::DecryptionResultRecipientsFeature
+ | GpgME::VerificationResultFileNameFeature
+ | GpgME::SignaturePkaFieldsFeature
+ | GpgME::SignatureAlgorithmFieldsFeature
+ | GpgME::FdPointerFeature
+ | GpgME::AuditLogFeature
+ | GpgME::GpgConfEngineFeature
+ | GpgME::CancelOperationAsyncFeature
+ | GpgME::NoEncryptToEncryptionFlagFeature
+ | GpgME::CardKeyFeature
+ | GpgME::AssuanEngineFeature
+ | GpgME::EphemeralKeylistModeFeature
+ | GpgME::ImportFromKeyserverFeature
+ | GpgME::G13VFSFeature
+ | GpgME::PasswdFeature
+ ;
+
+static const unsigned long supported_features2 = 0
+ | GpgME::BinaryAndFineGrainedIdentify
+ ;
+
+bool GpgME::hasFeature(unsigned long features)
+{
+ return features == (features & supported_features);
+}
+
+bool GpgME::hasFeature(unsigned long features, unsigned long features2)
+{
+ return features == (features & supported_features)
+ && features2 == (features2 & supported_features2)
+ ;
+}
diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h
new file mode 100644
index 0000000..b1e4f5f
--- /dev/null
+++ b/lang/cpp/src/context.h
@@ -0,0 +1,420 @@
+/*
+ context.h - wraps a gpgme key context
+ Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONTEXT_H__
+#define __GPGMEPP_CONTEXT_H__
+
+#include "global.h"
+
+#include "error.h"
+#include "verificationresult.h" // for Signature::Notation
+
+#include <memory>
+#include <vector>
+#include <utility>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Key;
+class Data;
+class TrustItem;
+class ProgressProvider;
+class PassphraseProvider;
+class EventLoopInteractor;
+class EditInteractor;
+class AssuanTransaction;
+
+class KeyListResult;
+class KeyGenerationResult;
+class ImportResult;
+class DecryptionResult;
+class VerificationResult;
+class SigningResult;
+class EncryptionResult;
+class VfsMountResult;
+
+class EngineInfo;
+
+class GPGMEPP_EXPORT Context
+{
+ explicit Context(gpgme_ctx_t);
+public:
+ //using GpgME::Protocol;
+
+ //
+ // Creation and destruction:
+ //
+
+ static Context *createForProtocol(Protocol proto);
+ static std::unique_ptr<Context> createForEngine(Engine engine, Error *err = 0);
+ virtual ~Context();
+
+ //
+ // Context Attributes
+ //
+
+ Protocol protocol() const;
+
+ void setArmor(bool useArmor);
+ bool armor() const;
+
+ void setTextMode(bool useTextMode);
+ bool textMode() const;
+
+ void setOffline(bool useOfflineMode);
+ bool offline() const;
+
+ enum CertificateInclusion {
+ DefaultCertificates = -256,
+ AllCertificatesExceptRoot = -2,
+ AllCertificates = -1,
+ NoCertificates = 0,
+ OnlySenderCertificate = 1
+ };
+ void setIncludeCertificates(int which);
+ int includeCertificates() const;
+
+ //using GpgME::KeyListMode;
+ void setKeyListMode(unsigned int keyListMode);
+ void addKeyListMode(unsigned int keyListMode);
+ unsigned int keyListMode() const;
+
+ /** Set the passphrase provider
+ *
+ * To avoid problems where a class using a context registers
+ * itself as the provider the Context does not take ownership
+ * of the provider and the caller must ensure that the provider
+ * is deleted if it is no longer needed.
+ */
+ void setPassphraseProvider(PassphraseProvider *provider);
+ PassphraseProvider *passphraseProvider() const;
+
+ /** Set the progress provider
+ *
+ * To avoid problems where a class using a context registers
+ * itself as the provider the Context does not take ownership
+ * of the provider and the caller must ensure that the provider
+ * is deleted if it is no longer needed.
+ */
+ void setProgressProvider(ProgressProvider *provider);
+ ProgressProvider *progressProvider() const;
+
+ void setManagedByEventLoopInteractor(bool managed);
+ bool managedByEventLoopInteractor() const;
+
+ GpgME::Error setLocale(int category, const char *value);
+
+ EngineInfo engineInfo() const;
+ GpgME::Error setEngineFileName(const char *filename);
+ GpgME::Error setEngineHomeDirectory(const char *filename);
+
+ enum PinentryMode{
+ PinentryDefault = 0,
+ PinentryAsk = 1,
+ PinentryCancel = 2,
+ PinentryError = 3,
+ PinentryLoopback = 4
+ };
+ GpgME::Error setPinentryMode(PinentryMode which);
+ PinentryMode pinentryMode() const;
+
+private:
+ friend class ::GpgME::EventLoopInteractor;
+ void installIOCallbacks(gpgme_io_cbs *iocbs);
+ void uninstallIOCallbacks();
+
+public:
+ //
+ //
+ // Key Management
+ //
+ //
+
+ //
+ // Key Listing
+ //
+
+ GpgME::Error startKeyListing(const char *pattern = 0, bool secretOnly = false);
+ GpgME::Error startKeyListing(const char *patterns[], bool secretOnly = false);
+
+ Key nextKey(GpgME::Error &e);
+
+ KeyListResult endKeyListing();
+ KeyListResult keyListResult() const;
+
+ Key key(const char *fingerprint, GpgME::Error &e, bool secret = false);
+
+ //
+ // Key Generation
+ //
+
+ KeyGenerationResult generateKey(const char *parameters, Data &pubKey);
+ GpgME::Error startKeyGeneration(const char *parameters, Data &pubkey);
+ KeyGenerationResult keyGenerationResult() const;
+
+ //
+ // Key Export
+ //
+
+ GpgME::Error exportPublicKeys(const char *pattern, Data &keyData);
+ GpgME::Error exportPublicKeys(const char *pattern[], Data &keyData);
+ GpgME::Error startPublicKeyExport(const char *pattern, Data &keyData);
+ GpgME::Error startPublicKeyExport(const char *pattern[], Data &keyData);
+
+ //
+ // Key Import
+ //
+
+ ImportResult importKeys(const Data &data);
+ ImportResult importKeys(const std::vector<Key> &keys);
+ GpgME::Error startKeyImport(const Data &data);
+ GpgME::Error startKeyImport(const std::vector<Key> &keys);
+ ImportResult importResult() const;
+
+ //
+ // Key Deletion
+ //
+
+ GpgME::Error deleteKey(const Key &key, bool allowSecretKeyDeletion = false);
+ GpgME::Error startKeyDeletion(const Key &key, bool allowSecretKeyDeletion = false);
+
+ //
+ // Passphrase changing
+ //
+
+ GpgME::Error passwd(const Key &key);
+ GpgME::Error startPasswd(const Key &key);
+
+ //
+ // Key Editing
+ //
+
+ GpgME::Error edit(const Key &key, std::unique_ptr<EditInteractor> function, Data &out);
+ GpgME::Error startEditing(const Key &key, std::unique_ptr<EditInteractor> function, Data &out);
+
+ // using TofuInfo::Policy
+ Error setTofuPolicy(const Key &k, unsigned int policy);
+ Error setTofuPolicyStart(const Key &k, unsigned int policy);
+
+ EditInteractor *lastEditInteractor() const;
+ std::unique_ptr<EditInteractor> takeLastEditInteractor();
+
+ //
+ // SmartCard Editing
+ //
+
+ GpgME::Error cardEdit(const Key &key, std::unique_ptr<EditInteractor> function, Data &out);
+ GpgME::Error startCardEditing(const Key &key, std::unique_ptr<EditInteractor> function, Data &out);
+
+ EditInteractor *lastCardEditInteractor() const;
+ std::unique_ptr<EditInteractor> takeLastCardEditInteractor();
+
+ //
+ // Trust Item Management
+ //
+
+ GpgME::Error startTrustItemListing(const char *pattern, int maxLevel);
+ TrustItem nextTrustItem(GpgME::Error &e);
+ GpgME::Error endTrustItemListing();
+
+ //
+ // Assuan Transactions
+ //
+
+ GpgME::Error assuanTransact(const char *command, std::unique_ptr<AssuanTransaction> transaction);
+ GpgME::Error assuanTransact(const char *command);
+ GpgME::Error startAssuanTransaction(const char *command, std::unique_ptr<AssuanTransaction> transaction);
+ GpgME::Error startAssuanTransaction(const char *command);
+
+ AssuanTransaction *lastAssuanTransaction() const;
+ std::unique_ptr<AssuanTransaction> takeLastAssuanTransaction();
+
+ //
+ //
+ // Crypto Operations
+ //
+ //
+
+ //
+ // Decryption
+ //
+
+ DecryptionResult decrypt(const Data &cipherText, Data &plainText);
+ GpgME::Error startDecryption(const Data &cipherText, Data &plainText);
+ DecryptionResult decryptionResult() const;
+
+ //
+ // Signature Verification
+ //
+
+ VerificationResult verifyDetachedSignature(const Data &signature, const Data &signedText);
+ VerificationResult verifyOpaqueSignature(const Data &signedData, Data &plainText);
+ GpgME::Error startDetachedSignatureVerification(const Data &signature, const Data &signedText);
+ GpgME::Error startOpaqueSignatureVerification(const Data &signedData, Data &plainText);
+ VerificationResult verificationResult() const;
+
+ //
+ // Combined Decryption and Signature Verification
+ //
+
+ std::pair<DecryptionResult, VerificationResult> decryptAndVerify(const Data &cipherText, Data &plainText);
+ GpgME::Error startCombinedDecryptionAndVerification(const Data &cipherText, Data &plainText);
+ // use verificationResult() and decryptionResult() to retrieve the result objects...
+
+ //
+ // Signing
+ //
+
+ void clearSigningKeys();
+ GpgME::Error addSigningKey(const Key &signer);
+ Key signingKey(unsigned int index) const;
+ std::vector<Key> signingKeys() const;
+
+ void clearSignatureNotations();
+ GpgME::Error addSignatureNotation(const char *name, const char *value, unsigned int flags = 0);
+ GpgME::Error addSignaturePolicyURL(const char *url, bool critical = false);
+ const char *signaturePolicyURL() const;
+ Notation signatureNotation(unsigned int index) const;
+ std::vector<Notation> signatureNotations() const;
+
+ //using GpgME::SignatureMode;
+ SigningResult sign(const Data &plainText, Data &signature, SignatureMode mode);
+ GpgME::Error startSigning(const Data &plainText, Data &signature, SignatureMode mode);
+ SigningResult signingResult() const;
+
+ //
+ // Encryption
+ //
+
+ enum EncryptionFlags {
+ None = 0,
+ AlwaysTrust = 1,
+ NoEncryptTo = 2,
+ Prepare = 4,
+ ExpectSign = 8,
+ NoCompress = 16,
+ Symmetric = 32
+ };
+ EncryptionResult encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+ GpgME::Error encryptSymmetrically(const Data &plainText, Data &cipherText);
+ GpgME::Error startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+ EncryptionResult encryptionResult() const;
+
+ //
+ // Combined Signing and Encryption
+ //
+
+ std::pair<SigningResult, EncryptionResult> signAndEncrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+ GpgME::Error startCombinedSigningAndEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
+ // use encryptionResult() and signingResult() to retrieve the result objects...
+
+ //
+ //
+ // Audit Log
+ //
+ //
+ enum AuditLogFlags {
+ HtmlAuditLog = 1,
+ AuditLogWithHelp = 128
+ };
+ GpgME::Error startGetAuditLog(Data &output, unsigned int flags = 0);
+ GpgME::Error getAuditLog(Data &output, unsigned int flags = 0);
+
+ //
+ //
+ // G13 crypto container operations
+ //
+ //
+ GpgME::Error createVFS(const char *containerFile, const std::vector<Key> &recipients);
+ VfsMountResult mountVFS(const char *containerFile, const char *mountDir);
+
+ // Spawn Engine
+ enum SpawnFlags {
+ SpawnNone = 0,
+ SpawnDetached = 1,
+ SpawnAllowSetFg = 2
+ };
+ /** Spwan the process \a file with arguments \a argv.
+ *
+ * If a data parameter is null the /dev/null will be
+ * used. (Or other platform stuff).
+ *
+ * @param file The executable to start.
+ * @param argv list of arguments file should be argv[0].
+ * @param input The data to be sent through stdin.
+ * @param output The data to be recieve the stdout.
+ * @param err The data to recieve stderr.
+ * @param flags Additional flags.
+ *
+ * @returns An error or empty error.
+ */
+ GpgME::Error spawn(const char *file, const char *argv[],
+ Data &input, Data &output, Data &err,
+ SpawnFlags flags);
+ /** Async variant of spawn. Immediately returns after starting the
+ * process. */
+ GpgME::Error spawnAsync(const char *file, const char *argv[],
+ Data &input, Data &output,
+ Data &err, SpawnFlags flags);
+ //
+ //
+ // Run Control
+ //
+ //
+
+ bool poll();
+ GpgME::Error wait();
+ GpgME::Error lastError() const;
+ GpgME::Error cancelPendingOperation();
+
+ class Private;
+ const Private *impl() const
+ {
+ return d;
+ }
+ Private *impl()
+ {
+ return d;
+ }
+private:
+ // Helper functions that need to be context because they rely
+ // on the "Friendlyness" of context to access the gpgme types.
+ gpgme_key_t *getKeysFromRecipients(const std::vector<Key> &recipients);
+
+private:
+ Private *const d;
+
+private: // disable...
+ Context(const Context &);
+ const Context &operator=(const Context &);
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::CertificateInclusion incl);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Context::AuditLogFlags flags);
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_CONTEXT_H__
diff --git a/lang/cpp/src/context_p.h b/lang/cpp/src/context_p.h
new file mode 100644
index 0000000..be34783
--- /dev/null
+++ b/lang/cpp/src/context_p.h
@@ -0,0 +1,84 @@
+/*
+ context_p.h - wraps a gpgme context (private part)
+ Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_CONTEXT_P_H__
+#define __GPGMEPP_CONTEXT_P_H__
+
+#include <context.h>
+#include <data.h>
+
+#include <gpgme.h>
+
+namespace GpgME
+{
+
+class Context::Private
+{
+public:
+ enum Operation {
+ None = 0,
+
+ Encrypt = 0x001,
+ Decrypt = 0x002,
+ Sign = 0x004,
+ Verify = 0x008,
+ DecryptAndVerify = Decrypt | Verify,
+ SignAndEncrypt = Sign | Encrypt,
+
+ Import = 0x010,
+ Export = 0x020, // no gpgme_export_result_t, but nevertheless...
+ Delete = 0x040, // no gpgme_delete_result_t, but nevertheless...
+
+ KeyGen = 0x080,
+ KeyList = 0x100,
+ TrustList = 0x200, // no gpgme_trustlist_result_t, but nevertheless...
+
+ Edit = 0x400, // no gpgme_edit_result_t, but nevertheless...
+ CardEdit = 0x800, // no gpgme_card_edit_result_t, but nevertheless...
+
+ GetAuditLog = 0x1000, // no gpgme_getauditlog_result_t, but nevertheless...
+
+ AssuanTransact = 0x2000,
+ Passwd = 0x4000, // no gpgme_passwd_result_t, but nevertheless...
+
+ CreateVFS = 0x4000,
+ MountVFS = 0x8000,
+
+ EndMarker
+ };
+
+ Private(gpgme_ctx_t c = 0);
+ ~Private();
+
+ gpgme_ctx_t ctx;
+ gpgme_io_cbs *iocbs;
+ Operation lastop;
+ gpgme_error_t lasterr;
+ Data lastAssuanInquireData;
+ std::unique_ptr<AssuanTransaction> lastAssuanTransaction;
+ std::unique_ptr<EditInteractor> lastEditInteractor, lastCardEditInteractor;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_CONTEXT_P_H__
diff --git a/lang/cpp/src/context_vanilla.cpp b/lang/cpp/src/context_vanilla.cpp
new file mode 100644
index 0000000..984d41b
--- /dev/null
+++ b/lang/cpp/src/context_vanilla.cpp
@@ -0,0 +1,33 @@
+/*
+ context_vanilla.cpp - wraps a gpgme key context, gpgme (vanilla)-specific functions
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <global.h>
+
+GIOChannel *GpgME::getGIOChannel(int)
+{
+ return 0;
+}
+
+QIODevice *GpgME::getQIODevice(int)
+{
+ return 0;
+}
diff --git a/lang/cpp/src/data.cpp b/lang/cpp/src/data.cpp
new file mode 100644
index 0000000..9527b2f
--- /dev/null
+++ b/lang/cpp/src/data.cpp
@@ -0,0 +1,222 @@
+/*
+ data.cpp - wraps a gpgme data object
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "data_p.h"
+#include <error.h>
+#include <interfaces/dataprovider.h>
+
+#include <gpgme.h>
+
+#ifndef NDEBUG
+#include <iostream>
+#endif
+
+GpgME::Data::Private::~Private()
+{
+ if (data) {
+ gpgme_data_release(data);
+ }
+}
+
+const GpgME::Data::Null GpgME::Data::null;
+
+GpgME::Data::Data()
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new(&data);
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(const Null &)
+ : d(new Private(0))
+{
+
+}
+
+GpgME::Data::Data(gpgme_data_t data)
+ : d(new Private(data))
+{
+
+}
+
+GpgME::Data::Data(const char *buffer, size_t size, bool copy)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new_from_mem(&data, buffer, size, int(copy));
+ std::string sizestr = std::to_string(size);
+ // Ignore errors as this is optional
+ gpgme_data_set_flag(data, "size-hint", sizestr.c_str());
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(const char *filename)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new(&data);
+ d.reset(new Private(e ? 0 : data));
+ if (!e) {
+ setFileName(filename);
+ }
+}
+
+GpgME::Data::Data(const char *filename, off_t offset, size_t length)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new_from_filepart(&data, filename, 0, offset, length);
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(FILE *fp)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new_from_stream(&data, fp);
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(FILE *fp, off_t offset, size_t length)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new_from_filepart(&data, 0, fp, offset, length);
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(int fd)
+{
+ gpgme_data_t data;
+ const gpgme_error_t e = gpgme_data_new_from_fd(&data, fd);
+ d.reset(new Private(e ? 0 : data));
+}
+
+GpgME::Data::Data(DataProvider *dp)
+{
+ d.reset(new Private);
+ if (!dp) {
+ return;
+ }
+ if (!dp->isSupported(DataProvider::Read)) {
+ d->cbs.read = 0;
+ }
+ if (!dp->isSupported(DataProvider::Write)) {
+ d->cbs.write = 0;
+ }
+ if (!dp->isSupported(DataProvider::Seek)) {
+ d->cbs.seek = 0;
+ }
+ if (!dp->isSupported(DataProvider::Release)) {
+ d->cbs.release = 0;
+ }
+ const gpgme_error_t e = gpgme_data_new_from_cbs(&d->data, &d->cbs, dp);
+ if (e) {
+ d->data = 0;
+ }
+ if (dp->isSupported(DataProvider::Seek)) {
+ off_t size = seek(0, SEEK_END);
+ seek(0, SEEK_SET);
+ std::string sizestr = std::to_string(size);
+ // Ignore errors as this is optional
+ gpgme_data_set_flag(d->data, "size-hint", sizestr.c_str());
+ }
+#ifndef NDEBUG
+ //std::cerr << "GpgME::Data(): DataProvider supports: "
+ // << ( d->cbs.read ? "read" : "no read" ) << ", "
+ // << ( d->cbs.write ? "write" : "no write" ) << ", "
+ // << ( d->cbs.seek ? "seek" : "no seek" ) << ", "
+ // << ( d->cbs.release ? "release" : "no release" ) << std::endl;
+#endif
+}
+
+bool GpgME::Data::isNull() const
+{
+ return !d || !d->data;
+}
+
+GpgME::Data::Encoding GpgME::Data::encoding() const
+{
+ switch (gpgme_data_get_encoding(d->data)) {
+ case GPGME_DATA_ENCODING_NONE: return AutoEncoding;
+ case GPGME_DATA_ENCODING_BINARY: return BinaryEncoding;
+ case GPGME_DATA_ENCODING_BASE64: return Base64Encoding;
+ case GPGME_DATA_ENCODING_ARMOR: return ArmorEncoding;
+ case GPGME_DATA_ENCODING_MIME: return MimeEncoding;
+ }
+ return AutoEncoding;
+}
+
+GpgME::Error GpgME::Data::setEncoding(Encoding enc)
+{
+ gpgme_data_encoding_t ge = GPGME_DATA_ENCODING_NONE;
+ switch (enc) {
+ case AutoEncoding: ge = GPGME_DATA_ENCODING_NONE; break;
+ case BinaryEncoding: ge = GPGME_DATA_ENCODING_BINARY; break;
+ case Base64Encoding: ge = GPGME_DATA_ENCODING_BASE64; break;
+ case ArmorEncoding: ge = GPGME_DATA_ENCODING_ARMOR; break;
+ case MimeEncoding: ge = GPGME_DATA_ENCODING_MIME; break;
+ }
+ return Error(gpgme_data_set_encoding(d->data, ge));
+}
+
+GpgME::Data::Type GpgME::Data::type() const
+{
+ if (isNull()) {
+ return Invalid;
+ }
+ switch (gpgme_data_identify(d->data, 0)) {
+ case GPGME_DATA_TYPE_INVALID: return Invalid;
+ case GPGME_DATA_TYPE_UNKNOWN: return Unknown;
+ case GPGME_DATA_TYPE_PGP_SIGNED: return PGPSigned;
+ case GPGME_DATA_TYPE_PGP_OTHER: return PGPOther;
+ case GPGME_DATA_TYPE_PGP_KEY: return PGPKey;
+ case GPGME_DATA_TYPE_CMS_SIGNED: return CMSSigned;
+ case GPGME_DATA_TYPE_CMS_ENCRYPTED: return CMSEncrypted;
+ case GPGME_DATA_TYPE_CMS_OTHER: return CMSOther;
+ case GPGME_DATA_TYPE_X509_CERT: return X509Cert;
+ case GPGME_DATA_TYPE_PKCS12: return PKCS12;
+ case GPGME_DATA_TYPE_PGP_ENCRYPTED: return PGPEncrypted;
+ case GPGME_DATA_TYPE_PGP_SIGNATURE: return PGPSignature;
+ }
+ return Invalid;
+}
+
+char *GpgME::Data::fileName() const
+{
+ return gpgme_data_get_file_name(d->data);
+}
+
+GpgME::Error GpgME::Data::setFileName(const char *name)
+{
+ return Error(gpgme_data_set_file_name(d->data, name));
+}
+
+ssize_t GpgME::Data::read(void *buffer, size_t length)
+{
+ return gpgme_data_read(d->data, buffer, length);
+}
+
+ssize_t GpgME::Data::write(const void *buffer, size_t length)
+{
+ return gpgme_data_write(d->data, buffer, length);
+}
+
+off_t GpgME::Data::seek(off_t offset, int whence)
+{
+ return gpgme_data_seek(d->data, offset, whence);
+}
diff --git a/lang/cpp/src/data.h b/lang/cpp/src/data.h
new file mode 100644
index 0000000..b2f2173
--- /dev/null
+++ b/lang/cpp/src/data.h
@@ -0,0 +1,126 @@
+/*
+ data.h - wraps a gpgme data object
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DATA_H__
+#define __GPGMEPP_DATA_H__
+
+#include "global.h"
+
+#include <sys/types.h> // for size_t, off_t
+#include <cstdio> // FILE
+#include <algorithm>
+#include <memory>
+
+namespace GpgME
+{
+
+class DataProvider;
+class Error;
+
+class GPGMEPP_EXPORT Data
+{
+ struct Null {
+ Null() {}
+ };
+public:
+ /* implicit */ Data(const Null &);
+ Data();
+ explicit Data(gpgme_data_t data);
+
+ // Memory-Based Data Buffers:
+ Data(const char *buffer, size_t size, bool copy = true);
+ explicit Data(const char *filename);
+ Data(const char *filename, off_t offset, size_t length);
+ Data(std::FILE *fp, off_t offset, size_t length);
+ // File-Based Data Buffers:
+ explicit Data(std::FILE *fp);
+ explicit Data(int fd);
+ // Callback-Based Data Buffers:
+ explicit Data(DataProvider *provider);
+
+ static const Null null;
+
+ const Data &operator=(Data other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Data &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ enum Encoding {
+ AutoEncoding,
+ BinaryEncoding,
+ Base64Encoding,
+ ArmorEncoding,
+ MimeEncoding
+ };
+ Encoding encoding() const;
+ Error setEncoding(Encoding encoding);
+
+ enum Type {
+ Invalid,
+ Unknown,
+ PGPSigned,
+ PGPOther,
+ PGPKey,
+ CMSSigned,
+ CMSEncrypted,
+ CMSOther,
+ X509Cert,
+ PKCS12,
+ PGPEncrypted,
+ PGPSignature,
+ };
+ Type type() const;
+
+ char *fileName() const;
+ Error setFileName(const char *name);
+
+ ssize_t read(void *buffer, size_t length);
+ ssize_t write(const void *buffer, size_t length);
+ off_t seek(off_t offset, int whence);
+
+ class Private;
+ Private *impl()
+ {
+ return d.get();
+ }
+ const Private *impl() const
+ {
+ return d.get();
+ }
+private:
+ std::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Data)
+
+#endif // __GPGMEPP_DATA_H__
diff --git a/lang/cpp/src/data_p.h b/lang/cpp/src/data_p.h
new file mode 100644
index 0000000..38ba55a
--- /dev/null
+++ b/lang/cpp/src/data_p.h
@@ -0,0 +1,40 @@
+/*
+ data_p.h - wraps a gpgme data object, private part -*- c++ -*-
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DATA_P_H__
+#define __GPGMEPP_DATA_P_H__
+
+#include <data.h>
+#include "callbacks.h"
+
+class GpgME::Data::Private
+{
+public:
+ explicit Private(gpgme_data_t d = 0)
+ : data(d), cbs(data_provider_callbacks) {}
+ ~Private();
+
+ gpgme_data_t data;
+ gpgme_data_cbs cbs;
+};
+
+#endif // __GPGMEPP_DATA_P_H__
diff --git a/lang/cpp/src/decryptionresult.cpp b/lang/cpp/src/decryptionresult.cpp
new file mode 100644
index 0000000..78a2b1b
--- /dev/null
+++ b/lang/cpp/src/decryptionresult.cpp
@@ -0,0 +1,240 @@
+/*
+ decryptionresult.cpp - wraps a gpgme keygen result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <decryptionresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <algorithm>
+#include <iterator>
+#include <cstring>
+#include <cstdlib>
+#include <istream>
+
+#include <string.h>
+
+class GpgME::DecryptionResult::Private
+{
+public:
+ explicit Private(const _gpgme_op_decrypt_result &r) : res(r)
+ {
+ if (res.unsupported_algorithm) {
+ res.unsupported_algorithm = strdup(res.unsupported_algorithm);
+ }
+ if (res.file_name) {
+ res.file_name = strdup(res.file_name);
+ }
+ //FIXME: copying gpgme_recipient_t objects invalidates the keyid member,
+ //thus we use _keyid for now (internal API)
+ for (gpgme_recipient_t r = res.recipients ; r ; r = r->next) {
+ recipients.push_back(*r);
+ }
+ res.recipients = 0;
+ }
+ ~Private()
+ {
+ if (res.unsupported_algorithm) {
+ std::free(res.unsupported_algorithm);
+ }
+ res.unsupported_algorithm = 0;
+ if (res.file_name) {
+ std::free(res.file_name);
+ }
+ res.file_name = 0;
+ }
+
+ _gpgme_op_decrypt_result res;
+ std::vector<_gpgme_recipient> recipients;
+};
+
+GpgME::DecryptionResult::DecryptionResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::DecryptionResult::DecryptionResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::DecryptionResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(*res));
+}
+
+make_standard_stuff(DecryptionResult)
+
+const char *GpgME::DecryptionResult::unsupportedAlgorithm() const
+{
+ return d ? d->res.unsupported_algorithm : 0 ;
+}
+
+bool GpgME::DecryptionResult::isWrongKeyUsage() const
+{
+ return d && d->res.wrong_key_usage;
+}
+
+const char *GpgME::DecryptionResult::fileName() const
+{
+ return d ? d->res.file_name : 0 ;
+}
+
+unsigned int GpgME::DecryptionResult::numRecipients() const
+{
+ return d ? d->recipients.size() : 0 ;
+}
+
+GpgME::DecryptionResult::Recipient GpgME::DecryptionResult::recipient(unsigned int idx) const
+{
+ if (d && idx < d->recipients.size()) {
+ return Recipient(&d->recipients[idx]);
+ }
+ return Recipient();
+}
+
+namespace
+{
+struct make_recipient {
+ GpgME::DecryptionResult::Recipient operator()(_gpgme_recipient &t)
+ {
+ return GpgME::DecryptionResult::Recipient(&t);
+ }
+};
+}
+
+std::vector<GpgME::DecryptionResult::Recipient> GpgME::DecryptionResult::recipients() const
+{
+ std::vector<Recipient> result;
+ if (d) {
+ result.reserve(d->recipients.size());
+ std::transform(d->recipients.begin(), d->recipients.end(),
+ std::back_inserter(result),
+ make_recipient());
+ }
+ return result;
+}
+
+class GpgME::DecryptionResult::Recipient::Private : public _gpgme_recipient
+{
+public:
+ Private(gpgme_recipient_t reci) : _gpgme_recipient(*reci) {}
+};
+
+GpgME::DecryptionResult::Recipient::Recipient()
+ : d()
+{
+
+}
+
+GpgME::DecryptionResult::Recipient::Recipient(gpgme_recipient_t r)
+ : d()
+{
+ if (r) {
+ d.reset(new Private(r));
+ }
+}
+
+bool GpgME::DecryptionResult::Recipient::isNull() const
+{
+ return !d;
+}
+
+const char *GpgME::DecryptionResult::Recipient::keyID() const
+{
+ //_keyid is internal API, but the public keyid is invalid after copying (see above)
+ if (d) {
+ return d->_keyid;
+ }
+ return 0;
+}
+
+const char *GpgME::DecryptionResult::Recipient::shortKeyID() const
+{
+ //_keyid is internal API, but the public keyid is invalid after copying (see above)
+ if (d) {
+ return d->_keyid + 8;
+ }
+ return 0;
+}
+
+unsigned int GpgME::DecryptionResult::Recipient::publicKeyAlgorithm() const
+{
+ if (d) {
+ return d->pubkey_algo;
+ }
+ return 0;
+}
+
+const char *GpgME::DecryptionResult::Recipient::publicKeyAlgorithmAsString() const
+{
+ if (d) {
+ return gpgme_pubkey_algo_name(d->pubkey_algo);
+ }
+ return 0;
+}
+
+GpgME::Error GpgME::DecryptionResult::Recipient::status() const
+{
+ if (d) {
+ return Error(d->status);
+ }
+ return Error();
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const DecryptionResult &result)
+{
+ os << "GpgME::DecryptionResult(";
+ if (!result.isNull()) {
+ os << "\n error: " << result.error()
+ << "\n fileName: " << protect(result.fileName())
+ << "\n unsupportedAlgorithm: " << protect(result.unsupportedAlgorithm())
+ << "\n isWrongKeyUsage: " << result.isWrongKeyUsage()
+ << "\n recipients:\n";
+ const std::vector<DecryptionResult::Recipient> recipients = result.recipients();
+ std::copy(recipients.begin(), recipients.end(),
+ std::ostream_iterator<DecryptionResult::Recipient>(os, "\n"));
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const DecryptionResult::Recipient &reci)
+{
+ os << "GpgME::DecryptionResult::Recipient(";
+ if (!reci.isNull()) {
+ os << "\n keyID: " << protect(reci.keyID())
+ << "\n shortKeyID: " << protect(reci.shortKeyID())
+ << "\n publicKeyAlgorithm: " << protect(reci.publicKeyAlgorithmAsString())
+ << "\n status: " << reci.status();
+ }
+ return os << ')';
+}
diff --git a/lang/cpp/src/decryptionresult.h b/lang/cpp/src/decryptionresult.h
new file mode 100644
index 0000000..60b78d9
--- /dev/null
+++ b/lang/cpp/src/decryptionresult.h
@@ -0,0 +1,130 @@
+/*
+ decryptionresult.h - wraps a gpgme keygen result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DECRYPTIONRESULT_H__
+#define __GPGMEPP_DECRYPTIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <vector>
+#include <algorithm>
+#include <iosfwd>
+#include <memory>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT DecryptionResult : public Result
+{
+public:
+ DecryptionResult();
+ DecryptionResult(gpgme_ctx_t ctx, int error);
+ DecryptionResult(gpgme_ctx_t ctx, const Error &err);
+ explicit DecryptionResult(const Error &err);
+
+ const DecryptionResult &operator=(DecryptionResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(DecryptionResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ GPGMEPP_DEPRECATED const char *unsupportedAlgortihm() const
+ {
+ return unsupportedAlgorithm();
+ }
+ const char *unsupportedAlgorithm() const;
+
+ GPGMEPP_DEPRECATED bool wrongKeyUsage() const
+ {
+ return isWrongKeyUsage();
+ }
+ bool isWrongKeyUsage() const;
+
+ const char *fileName() const;
+
+ class Recipient;
+
+ unsigned int numRecipients() const;
+ Recipient recipient(unsigned int idx) const;
+ std::vector<Recipient> recipients() const;
+
+private:
+ class Private;
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const DecryptionResult &result);
+
+class GPGMEPP_EXPORT DecryptionResult::Recipient
+{
+public:
+ Recipient();
+ explicit Recipient(gpgme_recipient_t reci);
+
+ const Recipient &operator=(Recipient other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Recipient &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ const char *keyID() const;
+ const char *shortKeyID() const;
+
+ unsigned int publicKeyAlgorithm() const;
+ const char *publicKeyAlgorithmAsString() const;
+
+ Error status() const;
+
+private:
+ class Private;
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const DecryptionResult::Recipient &reci);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(DecryptionResult)
+
+#endif // __GPGMEPP_DECRYPTIONRESULT_H__
diff --git a/lang/cpp/src/defaultassuantransaction.cpp b/lang/cpp/src/defaultassuantransaction.cpp
new file mode 100644
index 0000000..5bcf970
--- /dev/null
+++ b/lang/cpp/src/defaultassuantransaction.cpp
@@ -0,0 +1,78 @@
+/*
+ defaultassuantransaction.cpp - default Assuan Transaction that just stores data and status lines
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "defaultassuantransaction.h"
+#include "error.h"
+#include "data.h"
+
+#include <sstream>
+
+using namespace GpgME;
+
+DefaultAssuanTransaction::DefaultAssuanTransaction()
+ : AssuanTransaction(),
+ m_status(),
+ m_data()
+{
+
+}
+
+DefaultAssuanTransaction::~DefaultAssuanTransaction() {}
+
+Error DefaultAssuanTransaction::data(const char *data, size_t len)
+{
+ m_data.append(data, len);
+ return Error();
+}
+
+Data DefaultAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+ (void)name; (void)args; (void)err;
+ return Data::null;
+}
+
+Error DefaultAssuanTransaction::status(const char *status, const char *args)
+{
+ m_status.push_back(std::pair<std::string, std::string>(status, args));
+ return Error();
+}
+
+std::vector<std::string> DefaultAssuanTransaction::statusLine(const char *tag) const
+{
+ std::vector<std::string> result;
+ for (std::vector< std::pair<std::string, std::string> >::const_iterator it = m_status.begin(), end = m_status.end() ; it != end ; ++it) {
+ if (it->first == tag) {
+ result.push_back(it->second);
+ }
+ }
+ return result;
+}
+
+std::string DefaultAssuanTransaction::firstStatusLine(const char *tag) const
+{
+ for (std::vector< std::pair<std::string, std::string> >::const_iterator it = m_status.begin(), end = m_status.end() ; it != end ; ++it) {
+ if (it->first == tag) {
+ return it->second;
+ }
+ }
+ return std::string();
+}
diff --git a/lang/cpp/src/defaultassuantransaction.h b/lang/cpp/src/defaultassuantransaction.h
new file mode 100644
index 0000000..bf4b839
--- /dev/null
+++ b/lang/cpp/src/defaultassuantransaction.h
@@ -0,0 +1,65 @@
+/*
+ defaultassuantransaction.h - default Assuan Transaction that just stores data and status lines
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
+#define __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+#include <utility>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT DefaultAssuanTransaction : public AssuanTransaction
+{
+public:
+ explicit DefaultAssuanTransaction();
+ ~DefaultAssuanTransaction();
+
+ const std::vector< std::pair<std::string, std::string> > &statusLines() const
+ {
+ return m_status;
+ }
+ std::vector<std::string> statusLine(const char *tag) const;
+ std::string firstStatusLine(const char *tag) const;
+
+ const std::string &data() const
+ {
+ return m_data;
+ }
+
+private:
+ /* reimp */ Error data(const char *data, size_t datalen);
+ /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+ /* reimp */ Error status(const char *status, const char *args);
+
+private:
+ std::vector< std::pair<std::string, std::string> > m_status;
+ std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_DEFAULTASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/editinteractor.cpp b/lang/cpp/src/editinteractor.cpp
new file mode 100644
index 0000000..07dc26d
--- /dev/null
+++ b/lang/cpp/src/editinteractor.cpp
@@ -0,0 +1,339 @@
+/*
+ editinteractor.cpp - Interface for edit interactors
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "editinteractor.h"
+#include "callbacks.h"
+#include "error.h"
+
+#include <gpgme.h>
+
+#ifdef _WIN32
+# include <io.h>
+#include <windows.h>
+#else
+# include <unistd.h>
+#endif
+
+#include <cerrno>
+#include <cstring>
+
+#ifndef GPG_ERR_ALREADY_SIGNED
+# define GPG_ERR_ALREADY_SIGNED GPG_ERR_USER_1
+#endif
+
+using namespace GpgME;
+
+static const char *status_to_string(unsigned int status);
+static Error status_to_error(unsigned int status);
+
+class EditInteractor::Private
+{
+ friend class ::GpgME::EditInteractor;
+ friend class ::GpgME::CallbackHelper;
+ EditInteractor *const q;
+public:
+ explicit Private(EditInteractor *qq);
+ ~Private();
+
+private:
+ unsigned int state;
+ Error error;
+ std::FILE *debug;
+};
+
+class GpgME::CallbackHelper
+{
+private:
+ static int writeAll(int fd, const void *buf, size_t count)
+ {
+ size_t toWrite = count;
+ while (toWrite > 0) {
+ const int n = gpgme_io_write(fd, buf, toWrite);
+ if (n < 0) {
+ return n;
+ }
+ toWrite -= n;
+ }
+ return count;
+ }
+
+public:
+ static int edit_interactor_callback_impl(void *opaque, gpgme_status_code_t status, const char *args, int fd)
+ {
+ EditInteractor::Private *ei = (EditInteractor::Private *)opaque;
+
+ Error err = status_to_error(status);
+
+ if (!err) {
+
+ // advance to next state based on input:
+ const unsigned int oldState = ei->state;
+ ei->state = ei->q->nextState(status, args, err);
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: %u -> nextState( %s, %s ) -> %u\n",
+ oldState, status_to_string(status), args ? args : "<null>", ei->state);
+ }
+ if (err) {
+ ei->state = oldState;
+ goto error;
+ }
+
+ if (ei->state != oldState &&
+ // if there was an error from before, we stop here (### this looks weird, can this happen at all?)
+ ei->error.code() == GPG_ERR_NO_ERROR) {
+
+ // successful state change -> call action
+ if (const char *const result = ei->q->action(err)) {
+ if (err) {
+ goto error;
+ }
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: action result \"%s\"\n", result);
+ }
+ // if there's a result, write it:
+ if (*result) {
+ gpgme_err_set_errno(0);
+ const ssize_t len = std::strlen(result);
+ if (writeAll(fd, result, len) != len) {
+ err = Error::fromSystemError();
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
+ }
+ goto error;
+ }
+ }
+ gpgme_err_set_errno(0);
+ if (writeAll(fd, "\n", 1) != 1) {
+ err = Error::fromSystemError();
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
+ }
+ goto error;
+ }
+ } else {
+ if (err) {
+ goto error;
+ }
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: no action result\n");
+ }
+ }
+ } else {
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: no action executed\n");
+ }
+ }
+ }
+
+ error:
+ if (err) {
+ ei->error = err;
+ ei->state = EditInteractor::ErrorState;
+ }
+
+ if (ei->debug) {
+ std::fprintf(ei->debug, "EditInteractor: error now %u (%s)\n",
+ ei->error.encodedError(), gpgme_strerror(ei->error.encodedError()));
+ }
+
+ return ei->error.encodedError();
+ }
+};
+
+static gpgme_error_t edit_interactor_callback(void *opaque, gpgme_status_code_t status, const char *args, int fd)
+{
+ return CallbackHelper::edit_interactor_callback_impl(opaque, status, args, fd);
+}
+
+const gpgme_edit_cb_t GpgME::edit_interactor_callback = ::edit_interactor_callback;
+
+EditInteractor::Private::Private(EditInteractor *qq)
+ : q(qq),
+ state(StartState),
+ error(),
+ debug(0)
+{
+
+}
+
+EditInteractor::Private::~Private() {}
+
+EditInteractor::EditInteractor()
+ : d(new Private(this))
+{
+
+}
+
+EditInteractor::~EditInteractor()
+{
+ delete d;
+}
+
+unsigned int EditInteractor::state() const
+{
+ return d->state;
+}
+
+Error EditInteractor::lastError() const
+{
+ return d->error;
+}
+
+bool EditInteractor::needsNoResponse(unsigned int status) const
+{
+ switch (status) {
+ case GPGME_STATUS_ALREADY_SIGNED:
+ case GPGME_STATUS_ERROR:
+ case GPGME_STATUS_GET_BOOL:
+ case GPGME_STATUS_GET_LINE:
+ case GPGME_STATUS_KEY_CREATED:
+ case GPGME_STATUS_NEED_PASSPHRASE_SYM:
+ case GPGME_STATUS_SC_OP_FAILURE:
+ return false;
+ default:
+ return true;
+ }
+}
+
+// static
+Error status_to_error(unsigned int status)
+{
+ switch (status) {
+ case GPGME_STATUS_MISSING_PASSPHRASE:
+ return Error::fromCode(GPG_ERR_NO_PASSPHRASE);
+ case GPGME_STATUS_ALREADY_SIGNED:
+ return Error::fromCode(GPG_ERR_ALREADY_SIGNED);
+ case GPGME_STATUS_SIGEXPIRED:
+ return Error::fromCode(GPG_ERR_SIG_EXPIRED);
+ }
+ return Error();
+}
+
+void EditInteractor::setDebugChannel(std::FILE *debug)
+{
+ d->debug = debug;
+}
+
+static const char *const status_strings[] = {
+ "EOF",
+ /* mkstatus processing starts here */
+ "ENTER",
+ "LEAVE",
+ "ABORT",
+
+ "GOODSIG",
+ "BADSIG",
+ "ERRSIG",
+
+ "BADARMOR",
+
+ "RSA_OR_IDEA",
+ "KEYEXPIRED",
+ "KEYREVOKED",
+
+ "TRUST_UNDEFINED",
+ "TRUST_NEVER",
+ "TRUST_MARGINAL",
+ "TRUST_FULLY",
+ "TRUST_ULTIMATE",
+
+ "SHM_INFO",
+ "SHM_GET",
+ "SHM_GET_BOOL",
+ "SHM_GET_HIDDEN",
+
+ "NEED_PASSPHRASE",
+ "VALIDSIG",
+ "SIG_ID",
+ "ENC_TO",
+ "NODATA",
+ "BAD_PASSPHRASE",
+ "NO_PUBKEY",
+ "NO_SECKEY",
+ "NEED_PASSPHRASE_SYM",
+ "DECRYPTION_FAILED",
+ "DECRYPTION_OKAY",
+ "MISSING_PASSPHRASE",
+ "GOOD_PASSPHRASE",
+ "GOODMDC",
+ "BADMDC",
+ "ERRMDC",
+ "IMPORTED",
+ "IMPORT_OK",
+ "IMPORT_PROBLEM",
+ "IMPORT_RES",
+ "FILE_START",
+ "FILE_DONE",
+ "FILE_ERROR",
+
+ "BEGIN_DECRYPTION",
+ "END_DECRYPTION",
+ "BEGIN_ENCRYPTION",
+ "END_ENCRYPTION",
+
+ "DELETE_PROBLEM",
+ "GET_BOOL",
+ "GET_LINE",
+ "GET_HIDDEN",
+ "GOT_IT",
+ "PROGRESS",
+ "SIG_CREATED",
+ "SESSION_KEY",
+ "NOTATION_NAME",
+ "NOTATION_DATA",
+ "POLICY_URL",
+ "BEGIN_STREAM",
+ "END_STREAM",
+ "KEY_CREATED",
+ "USERID_HINT",
+ "UNEXPECTED",
+ "INV_RECP",
+ "NO_RECP",
+ "ALREADY_SIGNED",
+ "SIGEXPIRED",
+ "EXPSIG",
+ "EXPKEYSIG",
+ "TRUNCATED",
+ "ERROR",
+ "NEWSIG",
+ "REVKEYSIG",
+ "SIG_SUBPACKET",
+ "NEED_PASSPHRASE_PIN",
+ "SC_OP_FAILURE",
+ "SC_OP_SUCCESS",
+ "CARDCTRL",
+ "BACKUP_KEY_CREATED",
+ "PKA_TRUST_BAD",
+ "PKA_TRUST_GOOD",
+
+ "PLAINTEXT",
+};
+static const unsigned int num_status_strings = sizeof status_strings / sizeof * status_strings ;
+
+const char *status_to_string(unsigned int idx)
+{
+ if (idx < num_status_strings) {
+ return status_strings[idx];
+ } else {
+ return "(unknown)";
+ }
+}
diff --git a/lang/cpp/src/editinteractor.h b/lang/cpp/src/editinteractor.h
new file mode 100644
index 0000000..2122052
--- /dev/null
+++ b/lang/cpp/src/editinteractor.h
@@ -0,0 +1,68 @@
+/*
+ editinteractor.h - Interface for edit interactors
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_EDITINTERACTOR_H__
+#define __GPGMEPP_EDITINTERACTOR_H__
+
+#include "gpgmepp_export.h"
+
+#include <cstdio>
+
+namespace GpgME
+{
+
+class Error;
+class Context;
+class CallbackHelper;
+
+class GPGMEPP_EXPORT EditInteractor
+{
+ friend class ::GpgME::Context;
+ friend class ::GpgME::CallbackHelper;
+ EditInteractor(const EditInteractor &);
+ EditInteractor &operator=(const EditInteractor &);
+public:
+ EditInteractor();
+ virtual ~EditInteractor();
+
+ enum {
+ StartState = 0,
+ ErrorState = 0xFFFFFFFF
+ };
+
+ virtual const char *action(Error &err) const = 0;
+ virtual unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const = 0;
+
+ unsigned int state() const;
+ Error lastError() const;
+ bool needsNoResponse(unsigned int statusCode) const;
+
+ void setDebugChannel(std::FILE *file);
+
+private:
+ class Private;
+ Private *const d;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_EDITINTERACTOR_H__
diff --git a/lang/cpp/src/encryptionresult.cpp b/lang/cpp/src/encryptionresult.cpp
new file mode 100644
index 0000000..c4e7df5
--- /dev/null
+++ b/lang/cpp/src/encryptionresult.cpp
@@ -0,0 +1,159 @@
+/*
+ encryptionresult.cpp - wraps a gpgme verify result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <encryptionresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+#include <istream>
+#include <algorithm>
+#include <iterator>
+
+#include <string.h>
+
+class GpgME::EncryptionResult::Private
+{
+public:
+ explicit Private(const gpgme_encrypt_result_t r)
+ {
+ if (!r) {
+ return;
+ }
+ for (gpgme_invalid_key_t ik = r->invalid_recipients ; ik ; ik = ik->next) {
+ gpgme_invalid_key_t copy = new _gpgme_invalid_key(*ik);
+ if (ik->fpr) {
+ copy->fpr = strdup(ik->fpr);
+ }
+ copy->next = 0;
+ invalid.push_back(copy);
+ }
+ }
+ ~Private()
+ {
+ for (std::vector<gpgme_invalid_key_t>::iterator it = invalid.begin() ; it != invalid.end() ; ++it) {
+ std::free((*it)->fpr);
+ delete *it; *it = 0;
+ }
+ }
+
+ std::vector<gpgme_invalid_key_t> invalid;
+};
+
+GpgME::EncryptionResult::EncryptionResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::EncryptionResult::EncryptionResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::EncryptionResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_encrypt_result_t res = gpgme_op_encrypt_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(res));
+}
+
+make_standard_stuff(EncryptionResult)
+
+unsigned int GpgME::EncryptionResult::numInvalidRecipients() const
+{
+ return d ? d->invalid.size() : 0 ;
+}
+
+GpgME::InvalidRecipient GpgME::EncryptionResult::invalidEncryptionKey(unsigned int idx) const
+{
+ return InvalidRecipient(d, idx);
+}
+
+std::vector<GpgME::InvalidRecipient> GpgME::EncryptionResult::invalidEncryptionKeys() const
+{
+ if (!d) {
+ return std::vector<GpgME::InvalidRecipient>();
+ }
+ std::vector<GpgME::InvalidRecipient> result;
+ result.reserve(d->invalid.size());
+ for (unsigned int i = 0 ; i < d->invalid.size() ; ++i) {
+ result.push_back(InvalidRecipient(d, i));
+ }
+ return result;
+}
+
+GpgME::InvalidRecipient::InvalidRecipient(const std::shared_ptr<EncryptionResult::Private> &parent, unsigned int i)
+ : d(parent), idx(i)
+{
+
+}
+
+GpgME::InvalidRecipient::InvalidRecipient() : d(), idx(0) {}
+
+bool GpgME::InvalidRecipient::isNull() const
+{
+ return !d || idx >= d->invalid.size() ;
+}
+
+const char *GpgME::InvalidRecipient::fingerprint() const
+{
+ return isNull() ? 0 : d->invalid[idx]->fpr ;
+}
+
+GpgME::Error GpgME::InvalidRecipient::reason() const
+{
+ return Error(isNull() ? 0 : d->invalid[idx]->reason);
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const EncryptionResult &result)
+{
+ os << "GpgME::EncryptionResult(";
+ if (!result.isNull()) {
+ os << "\n error: " << result.error()
+ << "\n invalid recipients:\n";
+ const std::vector<InvalidRecipient> ir = result.invalidEncryptionKeys();
+ std::copy(ir.begin(), ir.end(),
+ std::ostream_iterator<InvalidRecipient>(os, "\n"));
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const InvalidRecipient &ir)
+{
+ os << "GpgME::InvalidRecipient(";
+ if (!ir.isNull()) {
+ os << "\n fingerprint: " << protect(ir.fingerprint())
+ << "\n reason: " << ir.reason()
+ << '\n';
+ }
+ return os << ')';
+}
diff --git a/lang/cpp/src/encryptionresult.h b/lang/cpp/src/encryptionresult.h
new file mode 100644
index 0000000..edc400f
--- /dev/null
+++ b/lang/cpp/src/encryptionresult.h
@@ -0,0 +1,113 @@
+/*
+ encryptionresult.h - wraps a gpgme sign result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_ENCRYPTIONRESULT_H__
+#define __GPGMEPP_ENCRYPTIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+class InvalidRecipient;
+
+class GPGMEPP_EXPORT EncryptionResult : public Result
+{
+public:
+ EncryptionResult();
+ EncryptionResult(gpgme_ctx_t ctx, int error);
+ EncryptionResult(gpgme_ctx_t ctx, const Error &error);
+ EncryptionResult(const Error &err);
+
+ const EncryptionResult &operator=(EncryptionResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(EncryptionResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ unsigned int numInvalidRecipients() const;
+
+ InvalidRecipient invalidEncryptionKey(unsigned int index) const;
+ std::vector<InvalidRecipient> invalidEncryptionKeys() const;
+
+ class Private;
+private:
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const EncryptionResult &result);
+
+class GPGMEPP_EXPORT InvalidRecipient
+{
+ friend class ::GpgME::EncryptionResult;
+ InvalidRecipient(const std::shared_ptr<EncryptionResult::Private> &parent, unsigned int index);
+public:
+ InvalidRecipient();
+
+ const InvalidRecipient &operator=(InvalidRecipient other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(InvalidRecipient &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ const char *fingerprint() const;
+ Error reason() const;
+
+private:
+ std::shared_ptr<EncryptionResult::Private> d;
+ unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const InvalidRecipient &recipient);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(EncryptionResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(InvalidRecipient)
+
+#endif // __GPGMEPP_ENCRYPTIONRESULT_H__
diff --git a/lang/cpp/src/engineinfo.cpp b/lang/cpp/src/engineinfo.cpp
new file mode 100644
index 0000000..c3b3e04
--- /dev/null
+++ b/lang/cpp/src/engineinfo.cpp
@@ -0,0 +1,88 @@
+/*
+ engineinfo.h
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "engineinfo.h"
+
+#include <gpgme.h>
+
+class GpgME::EngineInfo::Private
+{
+public:
+ Private(gpgme_engine_info_t engine = 0) : info(engine) {}
+ ~Private()
+ {
+ info = 0;
+ }
+
+ gpgme_engine_info_t info;
+};
+
+GpgME::EngineInfo::EngineInfo() : d() {}
+
+GpgME::EngineInfo::EngineInfo(gpgme_engine_info_t engine)
+ : d(new Private(engine))
+{
+
+}
+
+bool GpgME::EngineInfo::isNull() const
+{
+ return !d || !d->info;
+}
+
+GpgME::Protocol GpgME::EngineInfo::protocol() const
+{
+ if (isNull()) {
+ return UnknownProtocol;
+ }
+ switch (d->info->protocol) {
+ case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+ case GPGME_PROTOCOL_CMS: return CMS;
+ default:
+ return UnknownProtocol;
+ }
+}
+
+const char *GpgME::EngineInfo::fileName() const
+{
+ return isNull() ? 0 : d->info->file_name;
+}
+
+const char *GpgME::EngineInfo::version() const
+{
+ return isNull() ? 0 : d->info->version;
+}
+
+GpgME::EngineInfo::Version GpgME::EngineInfo::engineVersion() const
+{
+ return Version(version());
+}
+
+const char *GpgME::EngineInfo::requiredVersion() const
+{
+ return isNull() ? 0 : d->info->req_version;
+}
+
+const char *GpgME::EngineInfo::homeDirectory() const
+{
+ return isNull() ? 0 : d->info->home_dir;
+}
diff --git a/lang/cpp/src/engineinfo.h b/lang/cpp/src/engineinfo.h
new file mode 100644
index 0000000..72e125c
--- /dev/null
+++ b/lang/cpp/src/engineinfo.h
@@ -0,0 +1,126 @@
+/*
+ engineinfo.h
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_ENGINEINFO_H__
+#define __GPGMEPP_ENGINEINFO_H__
+
+#include "global.h"
+
+#include <memory>
+
+#include <algorithm>
+#include <string>
+#include <iostream>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT EngineInfo
+{
+public:
+ struct Version
+ {
+ int major, minor, patch;
+
+ Version(const std::string& version)
+ {
+ if (version.empty() ||
+ std::sscanf(version.c_str(), "%d.%d.%d", &major, &minor, &patch) != 3) {
+ major = 0;
+ minor = 0;
+ patch = 0;
+ }
+ }
+
+ bool operator < (const Version& other)
+ {
+ if (major < other.major)
+ return true;
+ if (minor < other.minor)
+ return true;
+ if (patch < other.patch)
+ return true;
+ return false;
+ }
+
+ bool operator < (const char* other)
+ {
+ return operator<(Version(other));
+ }
+
+ bool operator == (const Version& other)
+ {
+ return major == other.major
+ && minor == other.minor
+ && patch == other.patch;
+ }
+
+ bool operator == (const char* other)
+ {
+ return operator==(Version(other));
+ }
+
+ friend std::ostream& operator << (std::ostream& stream, const Version& ver)
+ {
+ stream << ver.major;
+ stream << '.';
+ stream << ver.minor;
+ stream << '.';
+ stream << ver.patch;
+ return stream;
+ }
+ };
+
+ EngineInfo();
+ explicit EngineInfo(gpgme_engine_info_t engine);
+
+ const EngineInfo &operator=(EngineInfo other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(EngineInfo &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ Protocol protocol() const;
+ const char *fileName() const;
+ const char *version() const;
+ Version engineVersion() const;
+ const char *requiredVersion() const;
+ const char *homeDirectory() const;
+
+private:
+ class Private;
+ std::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(EngineInfo)
+
+#endif // __GPGMEPP_ENGINEINFO_H__
diff --git a/lang/cpp/src/error.h b/lang/cpp/src/error.h
new file mode 100644
index 0000000..009fe20
--- /dev/null
+++ b/lang/cpp/src/error.h
@@ -0,0 +1,78 @@
+/*
+ error.h - wraps a gpgme error
+ Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_ERROR_H__
+#define __GPGMEPP_ERROR_H__
+
+#include "global.h"
+
+#include <string>
+#include <iosfwd>
+
+#include <gpg-error.h>
+
+#ifndef GPGMEPP_ERR_SOURCE_DEFAULT
+# define GPGMEPP_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_USER_1
+#endif
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Error
+{
+public:
+ Error() : mErr(0), mMessage() {}
+ explicit Error(unsigned int e) : mErr(e), mMessage() {}
+
+ const char *source() const;
+ const char *asString() const;
+
+ int code() const;
+ int sourceID() const;
+
+ bool isCanceled() const;
+
+ unsigned int encodedError() const
+ {
+ return mErr;
+ }
+ int toErrno() const;
+
+ static bool hasSystemError();
+ static Error fromSystemError(unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+ static void setSystemError(gpg_err_code_t err);
+ static void setErrno(int err);
+ static Error fromErrno(int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+ static Error fromCode(unsigned int err, unsigned int src = GPGMEPP_ERR_SOURCE_DEFAULT);
+
+ GPGMEPP_MAKE_SAFE_BOOL_OPERATOR(mErr &&!isCanceled())
+private:
+ unsigned int mErr;
+ mutable std::string mMessage;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Error &err);
+
+} // namespace GpgME
+
+#endif /* __GPGMEPP_ERROR_H__ */
diff --git a/lang/cpp/src/eventloopinteractor.cpp b/lang/cpp/src/eventloopinteractor.cpp
new file mode 100644
index 0000000..7ec258c
--- /dev/null
+++ b/lang/cpp/src/eventloopinteractor.cpp
@@ -0,0 +1,199 @@
+/*
+ eventloopinteractor.cpp
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <eventloopinteractor.h>
+
+#include <context.h>
+#include "context_p.h"
+#include <key.h>
+#include <trustitem.h>
+
+#include <gpgme.h>
+
+#include <vector>
+using std::vector;
+#ifndef NDEBUG
+# include <iostream>
+#endif
+#include <cassert>
+
+namespace GpgME
+{
+
+//
+// EventLoopInteractor::Private Declaration
+//
+
+class EventLoopInteractor::Private
+{
+public:
+ struct OneFD {
+ OneFD(int aFd, int aDir, gpgme_io_cb_t aFnc,
+ void *aFncData, void *aExternalTag)
+ : fd(aFd), dir(aDir), fnc(aFnc),
+ fncData(aFncData), externalTag(aExternalTag) {}
+ int fd;
+ int dir;
+ gpgme_io_cb_t fnc;
+ void *fncData;
+ void *externalTag;
+ };
+
+ vector<OneFD *> mCallbacks;
+
+ static void removeIOCb(void *tag);
+ static gpgme_error_t registerIOCb(void *data, int fd, int dir,
+ gpgme_io_cb_t fnc, void *fnc_data,
+ void **r_tag);
+ static void eventIOCb(void *, gpgme_event_io_t type, void *type_data);
+
+ static const gpgme_io_cbs iocbs;
+};
+
+const gpgme_io_cbs EventLoopInteractor::Private::iocbs = {
+ &EventLoopInteractor::Private::registerIOCb,
+ 0,
+ &EventLoopInteractor::Private::removeIOCb,
+ &EventLoopInteractor::Private::eventIOCb,
+ 0
+};
+
+//
+// EventLoopInteractor::Private IO Callback Implementations
+//
+
+gpgme_error_t EventLoopInteractor::Private::registerIOCb(void *, int fd, int dir,
+ gpgme_io_cb_t fnc, void *fnc_data,
+ void **r_tag)
+{
+ assert(instance()); assert(instance()->d);
+ bool ok = false;
+ void *etag = instance()->registerWatcher(fd, dir ? Read : Write, ok);
+ if (!ok) {
+ return gpgme_error(GPG_ERR_GENERAL);
+ }
+ instance()->d->mCallbacks.push_back(new OneFD(fd, dir, fnc, fnc_data, etag));
+ if (r_tag) {
+ *r_tag = instance()->d->mCallbacks.back();
+ }
+ return GPG_ERR_NO_ERROR;
+}
+
+void EventLoopInteractor::Private::removeIOCb(void *tag)
+{
+
+ if (!instance() || !instance()->d) {
+ return;
+ }
+ for (vector<OneFD *>::iterator it = instance()->d->mCallbacks.begin();
+ it != instance()->d->mCallbacks.end() ; ++it) {
+ if (*it == tag) {
+ instance()->unregisterWatcher((*it)->externalTag);
+ delete *it; *it = 0;
+ instance()->d->mCallbacks.erase(it);
+ return;
+ }
+ }
+}
+
+void EventLoopInteractor::Private::eventIOCb(void *data, gpgme_event_io_t type, void *type_data)
+{
+ assert(instance());
+ Context *ctx = static_cast<Context *>(data);
+ switch (type) {
+ case GPGME_EVENT_START: {
+ instance()->operationStartEvent(ctx);
+ // TODO: what's in type_data?
+ }
+ break;
+ case GPGME_EVENT_DONE: {
+ gpgme_error_t e = *static_cast<gpgme_error_t *>(type_data);
+ if (ctx && ctx->impl()) {
+ ctx->impl()->lasterr = e;
+ }
+ instance()->operationDoneEvent(ctx, Error(e));
+ }
+ break;
+ case GPGME_EVENT_NEXT_KEY: {
+ gpgme_key_t key = static_cast<gpgme_key_t>(type_data);
+ instance()->nextKeyEvent(ctx, Key(key, false));
+ }
+ break;
+ case GPGME_EVENT_NEXT_TRUSTITEM: {
+ gpgme_trust_item_t item = static_cast<gpgme_trust_item_t>(type_data);
+ instance()->nextTrustItemEvent(ctx, TrustItem(item));
+ gpgme_trust_item_unref(item);
+ }
+ break;
+ default: // warn
+ ;
+ }
+}
+
+//
+// EventLoopInteractor Implementation
+//
+
+EventLoopInteractor *EventLoopInteractor::mSelf = 0;
+
+EventLoopInteractor::EventLoopInteractor() : d(new Private)
+{
+ assert(!mSelf);
+ mSelf = this;
+}
+
+EventLoopInteractor::~EventLoopInteractor()
+{
+ // warn if there are still callbacks registered
+ mSelf = 0;
+ delete d;
+}
+
+void EventLoopInteractor::manage(Context *context)
+{
+ if (!context || context->managedByEventLoopInteractor()) {
+ return;
+ }
+ gpgme_io_cbs *iocbs = new gpgme_io_cbs(Private::iocbs);
+ iocbs->event_priv = context;
+ context->installIOCallbacks(iocbs);
+}
+
+void EventLoopInteractor::unmanage(Context *context)
+{
+ if (context) {
+ context->uninstallIOCallbacks();
+ }
+}
+
+void EventLoopInteractor::actOn(int fd, Direction dir)
+{
+ for (vector<Private::OneFD *>::const_iterator it = d->mCallbacks.begin();
+ it != d->mCallbacks.end() ; ++it) {
+ if ((*it)->fd == fd && ((*it)->dir ? Read : Write) == dir) {
+ (*((*it)->fnc))((*it)->fncData, fd);
+ break;
+ }
+ }
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/eventloopinteractor.h b/lang/cpp/src/eventloopinteractor.h
new file mode 100644
index 0000000..94821d6
--- /dev/null
+++ b/lang/cpp/src/eventloopinteractor.h
@@ -0,0 +1,156 @@
+/*
+ eventloopinteractor.h
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_EVENTLOOPINTERACTOR_H__
+#define __GPGMEPP_EVENTLOOPINTERACTOR_H__
+
+#include "gpgmepp_export.h"
+
+namespace GpgME
+{
+
+class Context;
+class Error;
+class TrustItem;
+class Key;
+
+/*! \file eventloopinteractor.h
+ \brief Abstract base class for gpgme's external event loop support
+
+ This class does most of the work involved with hooking GpgME++
+ up with external event loops, such as the GTK or Qt ones.
+
+ It actually provides two interfaces: An interface to the gpgme
+ IO Callback handling and one for gpgme events. The IO Callback
+ interface consists of the three methods \c actOn(), \c
+ registerWatcher() and \c unregisterWatcher(). The event
+ interface consists of the three methods \c nextTrustItemEvent(),
+ \c nextKeyEvent() and \c operationDoneEvent().
+
+ \sect General Usage
+
+ \c EventLoopInteractor is designed to be used as a
+ singleton. However, in order to make any use of it, you have to
+ subclass it and reimplement it's pure virtual methods (see
+ below). We suggest you keep the constructor protected and
+ provide a static \c instance() method that returns the single
+ instance. Alternatively, you can create an instance on the
+ stack, e.g. in \c main().
+
+ If you want \c EventLoopInteractor to manage a particular \c
+ Context, just call \c manage() on the \c Context. OTOH, if you
+ want to disable IO callbacks for a \c Context, use \c unmanage().
+
+ \sect IO Callback Interface
+
+ One part of this interface is represented by \c
+ registerWatcher() and \c unregisterWatcher(), both of which are
+ pure virtual. \c registerWatcher() should do anything necessary
+ to hook up watching of file descriptor \c fd for reading (\c dir
+ = \c Read) or writing (\c dir = Write) to the event loop you use
+ and return a tag identifying that particular watching process
+ uniquely. This could be the index into an array of objects you
+ use for that purpose or the address of such an object. E.g. in
+ Qt, you'd essentially just create a new \c QSocketNotifier:
+
+ \verbatim
+ void * registerWatcher( int fd, Direction dir ) {
+ return new QSocketNotifier( fd, dir == Read ? QSocketNotifier::Read : QSocketNotifier::Write );
+ // misses connecting to the activated() signal...
+ }
+ \endverbatim
+
+ which uses the address of the created object as unique tag. The
+ tag returned by \c registerWatcher is stored by \c
+ EventLoopInteractor and passed as argument to \c
+ unregisterWatcher(). So, in the picture above, you'd implement \c
+ unregisterWatcher() like this:
+
+ \verbatim
+ void unregisterWatcher( void * tag ) {
+ delete static_cast<QSocketNotifier*>( tag );
+ }
+ \endverbatim
+
+ The other part of the IO callback interface is \c actOn(), which
+ you should call if you receive notification from your event loop
+ about activity on file descriptor \c fd in direction \c dir. In
+ the picture above, you'd call this from the slot connected to
+ the socket notifier's \c activated() signal.
+
+ \note \c registerWatcher() as well as \c unregisterWatcher() may
+ be called from within \c actOn(), so be careful with
+ e.g. locking in threaded environments and keep in mind that the
+ object you used to find the \c fd and \c dir fo the \c actOn()
+ call might be deleted when \c actOn() returns!
+
+ \sect Event Handler Interface
+
+*/
+class GPGMEPP_EXPORT EventLoopInteractor
+{
+protected:
+ EventLoopInteractor();
+public:
+ virtual ~EventLoopInteractor();
+
+ static EventLoopInteractor *instance()
+ {
+ return mSelf;
+ }
+
+ void manage(Context *context);
+ void unmanage(Context *context);
+
+ enum Direction { Read, Write };
+protected:
+ //
+ // IO Notification Interface
+ //
+
+ /** Call this if your event loop detected activity on file
+ descriptor fd, with direction dir */
+ void actOn(int fd, Direction dir);
+
+ virtual void *registerWatcher(int fd, Direction dir, bool &ok) = 0;
+ virtual void unregisterWatcher(void *tag) = 0;
+
+ //
+ // Event Handler Interface
+ //
+
+ virtual void operationStartEvent(Context *context) = 0;
+ virtual void nextTrustItemEvent(Context *context, const TrustItem &item) = 0;
+ virtual void nextKeyEvent(Context *context, const Key &key) = 0;
+ virtual void operationDoneEvent(Context *context, const Error &e) = 0;
+
+private:
+ class Private;
+ friend class Private;
+ Private *const d;
+ static EventLoopInteractor *mSelf;
+};
+
+}
+
+#endif // __GPGMEPP_EVENTLOOPINTERACTOR_H__
diff --git a/lang/cpp/src/exception.cpp b/lang/cpp/src/exception.cpp
new file mode 100644
index 0000000..c687024
--- /dev/null
+++ b/lang/cpp/src/exception.cpp
@@ -0,0 +1,58 @@
+/*
+ exception.cpp - exception wrapping a gpgme error
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#include "exception.h"
+
+#include <gpgme.h>
+
+#include <sstream>
+
+using namespace GpgME;
+using namespace std; // only safe b/c it's so small a file!
+
+Exception::~Exception() throw() {}
+
+// static
+string Exception::make_message(const Error &err, const string &msg)
+{
+ return make_message(err, msg, NoOptions);
+}
+
+// static
+string Exception::make_message(const Error &err, const string &msg, Options opt)
+{
+ if (opt & MessageOnly) {
+ return msg;
+ }
+ char error_string[128];
+ error_string[0] = '\0';
+ gpgme_strerror_r(err.encodedError(), error_string, sizeof error_string);
+ error_string[sizeof error_string - 1] = '\0';
+ stringstream ss;
+ ss << gpgme_strsource(err.encodedError()) << ": ";
+ if (!msg.empty()) {
+ ss << msg << ": ";
+ }
+ ss << error_string << " (" << static_cast<unsigned long>(err.encodedError()) << ')';
+ return ss.str();
+}
diff --git a/lang/cpp/src/exception.h b/lang/cpp/src/exception.h
new file mode 100644
index 0000000..8f40b0e
--- /dev/null
+++ b/lang/cpp/src/exception.h
@@ -0,0 +1,68 @@
+/*
+ exception.h - exception wrapping a gpgme error
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_EXCEPTION_H__
+#define __GPGMEPP_EXCEPTION_H__
+
+#include "error.h"
+
+#include <stdexcept>
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Exception : public std::runtime_error
+{
+public:
+ enum Options {
+ NoOptions = 0x0,
+ MessageOnly = 0x1,
+
+ AllOptions = MessageOnly
+ };
+
+ explicit Exception(const GpgME::Error &err, const std::string &msg = std::string(), Options opt = NoOptions)
+ : std::runtime_error(make_message(err, msg, opt)), m_error(err), m_message(msg) {}
+
+ ~Exception() throw();
+
+ Error error() const
+ {
+ return m_error;
+ }
+ const std::string &message() const
+ {
+ return m_message;
+ }
+private:
+ static std::string make_message(const GpgME::Error &err, const std::string &msg);
+ static std::string make_message(const GpgME::Error &err, const std::string &msg, Options opt);
+private:
+ const GpgME::Error m_error;
+ const std::string m_message;
+};
+
+} // namespace GpgME
+
+#endif /* __GPGMEPP_EXCEPTION_H__ */
diff --git a/lang/cpp/src/global.h b/lang/cpp/src/global.h
new file mode 100644
index 0000000..15cc027
--- /dev/null
+++ b/lang/cpp/src/global.h
@@ -0,0 +1,218 @@
+/*
+ global.h - global gpgme functions and enums
+ Copyright (C) 2003, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_GLOBAL_H__
+#define __GPGMEPP_GLOBAL_H__
+
+#include "gpgmefw.h"
+#include "gpgmepp_export.h"
+
+#include <iosfwd>
+#include <cstring>
+
+namespace GpgME
+{
+class Error;
+class EngineInfo;
+class Context;
+}
+
+struct _GIOChannel;
+typedef struct _GIOChannel GIOChannel;
+class QIODevice;
+
+namespace GpgME
+{
+
+GPGMEPP_EXPORT void initializeLibrary();
+/*!
+ Initializes the library, returns Error::code() ==
+ GPG_ERR_USER_1 if underlying gpgme is too old.
+*/
+GPGMEPP_EXPORT Error initializeLibrary(int);
+
+enum Protocol { OpenPGP, CMS, UnknownProtocol };
+
+enum Engine { GpgEngine, GpgSMEngine, GpgConfEngine, UnknownEngine, AssuanEngine, G13Engine, SpawnEngine };
+
+enum KeyListMode {
+ Local = 0x1,
+ Extern = 0x2,
+ Signatures = 0x4,
+ SignatureNotations = 0x8,
+ Validate = 0x10,
+ Ephemeral = 0x20,
+ WithTofu = 0x40
+};
+
+enum SignatureMode { NormalSignatureMode, Detached, Clearsigned };
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Protocol proto);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Engine eng);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, KeyListMode mode);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, SignatureMode mode);
+
+GPGMEPP_EXPORT Error setDefaultLocale(int category, const char *value);
+
+GPGMEPP_EXPORT Context *wait(Error &e, bool hang = true);
+typedef void (*IdleFunction)(void);
+GPGMEPP_EXPORT IdleFunction registerIdleFunction(IdleFunction idleFunction);
+
+typedef void (*IOCallback)(void *data, int fd);
+
+GPGMEPP_EXPORT EngineInfo engineInfo(Protocol proto);
+GPGMEPP_EXPORT EngineInfo engineInfo(Engine engine);
+/** Wrapper around gpgme_get_dirinfo. What can be:
+homedir, sysconfdir, bindir, libexecdir, libdir,
+datadir, localedir, agent-socket, agent-ssh-socket,
+dirmngr-socket, uiserver-socket, gpgconf-name, gpg-name,
+gpgsm-name, g13-name
+
+This may be extended in the future.
+*/
+GPGMEPP_EXPORT const char *dirInfo(const char *what);
+
+GPGMEPP_EXPORT Error checkEngine(Protocol proto);
+GPGMEPP_EXPORT Error checkEngine(Engine engine);
+
+GPGMEPP_EXPORT GIOChannel *getGIOChannel(int fd);
+GPGMEPP_EXPORT QIODevice *getQIODevice(int fd);
+
+enum Feature {
+ ValidatingKeylistModeFeature = 0x00000001,
+ CancelOperationFeature = 0x00000002,
+ WrongKeyUsageFeature = 0x00000004,
+ DefaultCertificateInclusionFeature = 0x00000008,
+
+ GetSetEngineInfoFeature = 0x00000010,
+ EngineInfoHomeDirFeature = 0x00000020,
+ NoEncryptToEncryptionFlagFeature = 0x00000040,
+ EphemeralKeylistModeFeature = 0x00000080,
+
+ SetDataFileNameFeeature = 0x00000100,
+ VerificationResultFileNameFeature = 0x00000200,
+ DecryptionResultFileNameFeature = 0x00000400,
+ DecryptionResultRecipientsFeature = 0x00000800,
+
+ AuditLogFeature = 0x00001000,
+ GpgConfEngineFeature = 0x00002000,
+ CancelOperationAsyncFeature = 0x00004000,
+ AssuanEngineFeature = 0x00008000,
+
+ ClearAddGetSignatureNotationsFeature = 0x00010000,
+ SignatureNotationsKeylistModeFeature = 0x00020000,
+ KeySignatureNotationsFeature = 0x00040000,
+ SignatureNotationsFlagsFeature = 0x00080000,
+ SignatureNotationsCriticalFlagFeature = 0x00100000,
+ SignatureNotationsHumanReadableFlagFeature = 0x00200000,
+ CardKeyFeature = 0x00400000,
+ ImportFromKeyserverFeature = 0x00800000,
+
+ KeyIsQualifiedFeature = 0x01000200,
+ SubkeyIsQualifiedFeature = 0x02000000,
+ SignaturePkaFieldsFeature = 0x04000000,
+ SignatureAlgorithmFieldsFeature = 0x08000000,
+
+ FdPointerFeature = 0x10000000,
+ G13VFSFeature = 0x20000000,
+ PasswdFeature = 0x40000000, // gpgme >= 1.3.0
+ // unusable (max value)
+
+ FeatureMaxValue = 0x80000000
+};
+enum Feature2 {
+ BinaryAndFineGrainedIdentify = 0x00000001, // gpgme >= 1.7.0
+ Feature2MaxValue = 0x80000000
+};
+
+// use hasFeature( unsigned long, unsigned long ) instead
+GPGMEPP_DEPRECATED_EXPORT bool hasFeature(unsigned long feature);
+GPGMEPP_EXPORT bool hasFeature(unsigned long feature, unsigned long feature2);
+
+} // namespace GpgME
+
+# ifndef GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION
+# define GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION( Class ) \
+ namespace std { template <> inline void swap< GpgME::Class >( GpgME::Class & lhs, GpgME::Class & rhs ) { lhs.swap( rhs ); } }
+# endif
+
+# ifndef GPGMEPP_MAKE_SAFE_BOOL_OPERATOR
+# define GPGMEPP_MAKE_SAFE_BOOL_OPERATOR( Cond ) \
+ private: \
+ struct __safe_bool_dummy__ { void nonnull() {} }; \
+ typedef void ( __safe_bool_dummy__::*unspecified_bool_type )(); \
+ public: \
+ operator unspecified_bool_type() const { return ( Cond ) ? &__safe_bool_dummy__::nonnull : 0 ; }
+# endif
+
+inline int _gpgmepp_strcmp(const char *s1, const char *s2)
+{
+ return s1 ? s2 ? std::strcmp(s1, s2) : 1 : s2 ? -1 : 0;
+}
+
+#define _GPGMEPP_MAKE_STRCMP( Name, expr, cmp ) \
+ template <template <typename U> class Op> \
+ struct Name { \
+ typedef bool result_type; \
+ \
+ bool operator()( const char * lhs, const char * rhs ) const { \
+ return Op<int>()( cmp, 0 ); \
+ } \
+ \
+ bool operator()( const std::string & lhs, const std::string & rhs ) const { \
+ return operator()( lhs.c_str(), rhs.c_str() ); \
+ } \
+ bool operator()( const char * lhs, const std::string & rhs ) const { \
+ return operator()( lhs, rhs.c_str() ); \
+ } \
+ bool operator()( const std::string & lhs, const char * rhs ) const { \
+ return operator()( lhs.c_str(), rhs ); \
+ } \
+ \
+ template <typename T> \
+ bool operator()( const T & lhs, const T & rhs ) const { \
+ return operator()( (lhs expr), (rhs expr) ); \
+ } \
+ template <typename T> \
+ bool operator()( const T & lhs, const char * rhs ) const { \
+ return operator()( (lhs expr), rhs ); \
+ } \
+ template <typename T> \
+ bool operator()( const char * lhs, const T & rhs ) const { \
+ return operator()( lhs, (rhs expr) ); \
+ } \
+ template <typename T> \
+ bool operator()( const T & lhs, const std::string & rhs ) const { \
+ return operator()( (lhs expr), rhs ); \
+ } \
+ template <typename T> \
+ bool operator()( const std::string & lhs, const T & rhs ) const { \
+ return operator()( lhs, (rhs expr) ); \
+ } \
+ }
+
+#define GPGMEPP_MAKE_STRCMP( Name, expr ) \
+ _GPGMEPP_MAKE_STRCMP( Name, expr, _gpgmepp_strcmp( lhs, rhs ) )
+
+
+#endif // __GPGMEPP_GLOBAL_H__
diff --git a/lang/cpp/src/gpgadduserideditinteractor.cpp b/lang/cpp/src/gpgadduserideditinteractor.cpp
new file mode 100644
index 0000000..43c8592
--- /dev/null
+++ b/lang/cpp/src/gpgadduserideditinteractor.cpp
@@ -0,0 +1,189 @@
+/*
+ gpgadduserideditinteractor.cpp - Edit Interactor to add a new UID to an OpenPGP key
+ Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgadduserideditinteractor.h"
+
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgAddUserIDEditInteractor::GpgAddUserIDEditInteractor()
+ : EditInteractor(),
+ m_name(),
+ m_email(),
+ m_comment()
+{
+
+}
+
+GpgAddUserIDEditInteractor::~GpgAddUserIDEditInteractor() {}
+
+void GpgAddUserIDEditInteractor::setNameUtf8(const std::string &name)
+{
+ m_name = name;
+}
+
+void GpgAddUserIDEditInteractor::setEmailUtf8(const std::string &email)
+{
+ m_email = email;
+}
+
+void GpgAddUserIDEditInteractor::setCommentUtf8(const std::string &comment)
+{
+ m_comment = comment;
+}
+
+// work around --enable-final
+namespace GpgAddUserIDEditInteractor_Private
+{
+enum {
+ START = EditInteractor::StartState,
+ COMMAND,
+ NAME,
+ EMAIL,
+ COMMENT,
+ QUIT,
+ SAVE,
+
+ ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgAddUserIDEditInteractor::action(Error &err) const
+{
+
+ using namespace GpgAddUserIDEditInteractor_Private;
+
+ switch (state()) {
+ case COMMAND:
+ return "adduid";
+ case NAME:
+ return m_name.c_str();
+ case EMAIL:
+ return m_email.c_str();
+ case COMMENT:
+ return m_comment.c_str();
+ case QUIT:
+ return "quit";
+ case SAVE:
+ return "Y";
+ case START:
+ case ERROR:
+ return 0;
+ default:
+ err = Error::fromCode(GPG_ERR_GENERAL);
+ return 0;
+ }
+}
+
+unsigned int GpgAddUserIDEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+ static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+ static const Error INV_NAME_ERROR = Error::fromCode(GPG_ERR_INV_NAME);
+ static const Error INV_EMAIL_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
+ static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
+
+ if (needsNoResponse(status)) {
+ return state();
+ }
+
+ using namespace GpgAddUserIDEditInteractor_Private;
+
+ switch (state()) {
+ case START:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return COMMAND;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case COMMAND:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.name") == 0) {
+ return NAME;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case NAME:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.email") == 0) {
+ return EMAIL;
+ }
+ err = GENERAL_ERROR;
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.name") == 0) {
+ err = INV_NAME_ERROR;
+ }
+ return ERROR;
+ case EMAIL:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.comment") == 0) {
+ return COMMENT;
+ }
+ err = GENERAL_ERROR;
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.email") == 0) {
+ err = INV_EMAIL_ERROR;
+ }
+ return ERROR;
+ case COMMENT:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = GENERAL_ERROR;
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.comment") == 0) {
+ err = INV_COMMENT_ERROR;
+ }
+ return ERROR;
+ case QUIT:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "keyedit.save.okay") == 0) {
+ return SAVE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case ERROR:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = lastError();
+ return ERROR;
+ default:
+ err = GENERAL_ERROR;
+ return ERROR;
+ }
+}
diff --git a/lang/cpp/src/gpgadduserideditinteractor.h b/lang/cpp/src/gpgadduserideditinteractor.h
new file mode 100644
index 0000000..12b6e46
--- /dev/null
+++ b/lang/cpp/src/gpgadduserideditinteractor.h
@@ -0,0 +1,67 @@
+/*
+ gpgadduserideditinteractor.h - Edit Interactor to add a new UID to an OpenPGP key
+ Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
+#define __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgAddUserIDEditInteractor : public EditInteractor
+{
+public:
+ explicit GpgAddUserIDEditInteractor();
+ ~GpgAddUserIDEditInteractor();
+
+ void setNameUtf8(const std::string &name);
+ const std::string &nameUtf8() const
+ {
+ return m_name;
+ }
+
+ void setEmailUtf8(const std::string &email);
+ const std::string &emailUtf8() const
+ {
+ return m_email;
+ }
+
+ void setCommentUtf8(const std::string &comment);
+ const std::string &commentUtf8() const
+ {
+ return m_comment;
+ }
+
+private:
+ /* reimp */ const char *action(Error &err) const;
+ /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+ std::string m_name, m_email, m_comment;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGADDUSERIDEDITINTERACTOR_H__
diff --git a/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp b/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp
new file mode 100644
index 0000000..4739aa2
--- /dev/null
+++ b/lang/cpp/src/gpgagentgetinfoassuantransaction.cpp
@@ -0,0 +1,119 @@
+/*
+ gpgagentgetinfoassuantransaction.cpp - Assuan Transaction to get information from gpg-agent
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgagentgetinfoassuantransaction.h"
+#include "error.h"
+#include "data.h"
+#include "util.h"
+
+#include <assert.h>
+
+#include <sstream>
+
+using namespace GpgME;
+
+GpgAgentGetInfoAssuanTransaction::GpgAgentGetInfoAssuanTransaction(InfoItem item)
+ : AssuanTransaction(),
+ m_item(item),
+ m_command(),
+ m_data()
+{
+
+}
+
+GpgAgentGetInfoAssuanTransaction::~GpgAgentGetInfoAssuanTransaction() {}
+
+std::string GpgAgentGetInfoAssuanTransaction::version() const
+{
+ if (m_item == Version) {
+ return m_data;
+ } else {
+ return std::string();
+ }
+}
+
+unsigned int GpgAgentGetInfoAssuanTransaction::pid() const
+{
+ if (m_item == Pid) {
+ return to_pid(m_data);
+ } else {
+ return 0U;
+ }
+}
+
+std::string GpgAgentGetInfoAssuanTransaction::socketName() const
+{
+ if (m_item == SocketName) {
+ return m_data;
+ } else {
+ return std::string();
+ }
+}
+
+std::string GpgAgentGetInfoAssuanTransaction::sshSocketName() const
+{
+ if (m_item == SshSocketName) {
+ return m_data;
+ } else {
+ return std::string();
+ }
+}
+
+static const char *const gpgagent_getinfo_tokens[] = {
+ "version",
+ "pid",
+ "socket_name",
+ "ssh_socket_name",
+ "scd_running",
+};
+
+void GpgAgentGetInfoAssuanTransaction::makeCommand() const
+{
+ assert(m_item >= 0);
+ assert(m_item < LastInfoItem);
+ m_command = "GETINFO ";
+ m_command += gpgagent_getinfo_tokens[m_item];
+}
+
+const char *GpgAgentGetInfoAssuanTransaction::command() const
+{
+ makeCommand();
+ return m_command.c_str();
+}
+
+Error GpgAgentGetInfoAssuanTransaction::data(const char *data, size_t len)
+{
+ m_data.append(data, len);
+ return Error();
+}
+
+Data GpgAgentGetInfoAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+ (void)name; (void)args; (void)err;
+ return Data::null;
+}
+
+Error GpgAgentGetInfoAssuanTransaction::status(const char *status, const char *args)
+{
+ (void)status; (void)args;
+ return Error();
+}
diff --git a/lang/cpp/src/gpgagentgetinfoassuantransaction.h b/lang/cpp/src/gpgagentgetinfoassuantransaction.h
new file mode 100644
index 0000000..9e3e958
--- /dev/null
+++ b/lang/cpp/src/gpgagentgetinfoassuantransaction.h
@@ -0,0 +1,73 @@
+/*
+ gpgagentgetinfoassuantransaction.h - Assuan Transaction to get information from gpg-agent
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
+#define __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgAgentGetInfoAssuanTransaction : public AssuanTransaction
+{
+public:
+ enum InfoItem {
+ Version, // string
+ Pid, // unsigned long
+ SocketName, // string (path)
+ SshSocketName, // string (path)
+ ScdRunning, // (none, returns GPG_ERR_GENERAL when scdaemon isn't running)
+ //CommandHasOption, // not supported
+
+ LastInfoItem
+ };
+
+ explicit GpgAgentGetInfoAssuanTransaction(InfoItem item);
+ ~GpgAgentGetInfoAssuanTransaction();
+
+ std::string version() const;
+ unsigned int pid() const;
+ std::string socketName() const;
+ std::string sshSocketName() const;
+
+private:
+ /* reimp */ const char *command() const;
+ /* reimp */ Error data(const char *data, size_t datalen);
+ /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+ /* reimp */ Error status(const char *status, const char *args);
+
+private:
+ void makeCommand() const;
+
+private:
+ InfoItem m_item;
+ mutable std::string m_command;
+ std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGAGENTGETINFOASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/gpgmefw.h b/lang/cpp/src/gpgmefw.h
new file mode 100644
index 0000000..cbdd444
--- /dev/null
+++ b/lang/cpp/src/gpgmefw.h
@@ -0,0 +1,70 @@
+/*
+ gpgmefw.h - Forwards declarations for gpgme (0.3 and 0.4)
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGMEFW_H__
+#define __GPGMEPP_GPGMEFW_H__
+
+struct gpgme_context;
+typedef gpgme_context *gpgme_ctx_t;
+
+struct gpgme_data;
+typedef gpgme_data *gpgme_data_t;
+
+struct gpgme_io_cbs;
+
+struct _gpgme_key;
+typedef struct _gpgme_key *gpgme_key_t;
+
+struct _gpgme_trust_item;
+typedef struct _gpgme_trust_item *gpgme_trust_item_t;
+
+struct _gpgme_subkey;
+typedef struct _gpgme_subkey *gpgme_sub_key_t;
+
+struct _gpgme_user_id;
+typedef struct _gpgme_user_id *gpgme_user_id_t;
+
+struct _gpgme_key_sig;
+typedef struct _gpgme_key_sig *gpgme_key_sig_t;
+
+struct _gpgme_sig_notation;
+typedef struct _gpgme_sig_notation *gpgme_sig_notation_t;
+
+struct _gpgme_engine_info;
+typedef struct _gpgme_engine_info *gpgme_engine_info_t;
+
+struct _gpgme_op_keylist_result;
+typedef struct _gpgme_op_keylist_result *gpgme_keylist_result_t;
+
+struct _gpgme_recipient;
+typedef struct _gpgme_recipient *gpgme_recipient_t;
+
+struct gpgme_conf_opt;
+typedef struct gpgme_conf_opt *gpgme_conf_opt_t;
+
+struct gpgme_conf_comp;
+typedef struct gpgme_conf_comp *gpgme_conf_comp_t;
+
+struct gpgme_conf_arg;
+typedef struct gpgme_conf_arg *gpgme_conf_arg_t;
+
+#endif // __GPGMEPP_GPGMEFW_H__
diff --git a/lang/cpp/src/gpgmepp_export.h b/lang/cpp/src/gpgmepp_export.h
new file mode 100644
index 0000000..d660310
--- /dev/null
+++ b/lang/cpp/src/gpgmepp_export.h
@@ -0,0 +1,73 @@
+/*gpgmepp_export.h - Export macros for gpgmepp
+ Copyright (C) 2016, Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GPGMEPP_EXPORT_H
+#define GPGMEPP_EXPORT_H
+
+#ifdef GPGMEPP_STATIC_DEFINE
+# define GPGMEPP_EXPORT
+# define GPGMEPP_NO_EXPORT
+#else
+# ifndef GPGMEPP_EXPORT
+# ifdef BUILDING_GPGMEPP
+ /* We are building this library */
+# ifdef WIN32
+# define GPGMEPP_EXPORT __declspec(dllexport)
+# else
+# define GPGMEPP_EXPORT __attribute__((visibility("default")))
+# endif
+# else
+ /* We are using this library */
+# ifdef WIN32
+# define GPGMEPP_EXPORT __declspec(dllimport)
+# else
+# define GPGMEPP_EXPORT __attribute__((visibility("default")))
+# endif
+# endif
+# endif
+
+# ifndef GPGMEPP_NO_EXPORT
+# ifdef WIN32
+# define GPGMEPP_NO_EXPORT
+# else
+# define GPGMEPP_NO_EXPORT __attribute__((visibility("hidden")))
+# endif
+# endif
+#endif
+
+#ifndef GPGMEPP_DEPRECATED
+# define GPGMEPP_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#ifndef GPGMEPP_DEPRECATED_EXPORT
+# define GPGMEPP_DEPRECATED_EXPORT GPGMEPP_EXPORT GPGMEPP_DEPRECATED
+#endif
+
+#ifndef GPGMEPP_DEPRECATED_NO_EXPORT
+# define GPGMEPP_DEPRECATED_NO_EXPORT GPGMEPP_NO_EXPORT GPGMEPP_DEPRECATED
+#endif
+
+#define DEFINE_NO_DEPRECATED 0
+#if DEFINE_NO_DEPRECATED
+# define GPGMEPP_NO_DEPRECATED
+#endif
+
+#endif
diff --git a/lang/cpp/src/gpgmepp_version.h.in b/lang/cpp/src/gpgmepp_version.h.in
new file mode 100644
index 0000000..3c33a30
--- /dev/null
+++ b/lang/cpp/src/gpgmepp_version.h.in
@@ -0,0 +1,32 @@
+/*gpgmepp_version.h - Version macros for gpgmepp
+ Copyright (C) 2016, Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef GPGMEPP_VERSION_H
+#define GPGMEPP_VERSION_H
+
+#define GPGMEPP_VERSION_STRING "@LIBGPGMEPP_LT_CURRENT@.@LIBGPGMEPP_LT_AGE@.@LIBGPGMEPP_LT_REVISION@"
+#define GPGMEPP_VERSION_MAJOR @LIBGPGMEPP_LT_CURRENT@
+#define GPGMEPP_VERSION_MINOR @LIBGPGMEPP_LT_AGE@
+#define GPGMEPP_VERSION_PATCH @LIBGPGMEPP_LT_REVISION@
+#define GPGMEPP_VERSION ((@LIBGPGMEPP_LT_CURRENT@<<16)|(@LIBGPGMEPP_LT_AGE@<<8)|(@LIBGPGMEPP_LT_REVISION@))
+
+#endif
diff --git a/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp b/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp
new file mode 100644
index 0000000..8af897c
--- /dev/null
+++ b/lang/cpp/src/gpgsetexpirytimeeditinteractor.cpp
@@ -0,0 +1,141 @@
+/*
+ gpgsetexpirytimeeditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsetexpirytimeeditinteractor.h"
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgSetExpiryTimeEditInteractor::GpgSetExpiryTimeEditInteractor(const std::string &t)
+ : EditInteractor(),
+ m_strtime(t)
+{
+
+}
+
+GpgSetExpiryTimeEditInteractor::~GpgSetExpiryTimeEditInteractor() {}
+
+// work around --enable-final
+namespace GpgSetExpiryTimeEditInteractor_Private
+{
+enum {
+ START = EditInteractor::StartState,
+ COMMAND,
+ DATE,
+ QUIT,
+ SAVE,
+
+ ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgSetExpiryTimeEditInteractor::action(Error &err) const
+{
+
+ using namespace GpgSetExpiryTimeEditInteractor_Private;
+
+ switch (state()) {
+ case COMMAND:
+ return "expire";
+ case DATE:
+ return m_strtime.c_str();
+ case QUIT:
+ return "quit";
+ case SAVE:
+ return "Y";
+ case START:
+ case ERROR:
+ return 0;
+ default:
+ err = Error::fromCode(GPG_ERR_GENERAL);
+ return 0;
+ }
+}
+
+unsigned int GpgSetExpiryTimeEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+ static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+ static const Error INV_TIME_ERROR = Error::fromCode(GPG_ERR_INV_TIME);
+
+ if (needsNoResponse(status)) {
+ return state();
+ }
+
+ using namespace GpgSetExpiryTimeEditInteractor_Private;
+
+ switch (state()) {
+ case START:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return COMMAND;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case COMMAND:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.valid") == 0) {
+ return DATE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case DATE:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ } else if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keygen.valid")) {
+ err = INV_TIME_ERROR;
+ return ERROR;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case QUIT:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "keyedit.save.okay") == 0) {
+ return SAVE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case ERROR:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = lastError();
+ return ERROR;
+ default:
+ err = GENERAL_ERROR;
+ return ERROR;
+ }
+}
diff --git a/lang/cpp/src/gpgsetexpirytimeeditinteractor.h b/lang/cpp/src/gpgsetexpirytimeeditinteractor.h
new file mode 100644
index 0000000..670b445
--- /dev/null
+++ b/lang/cpp/src/gpgsetexpirytimeeditinteractor.h
@@ -0,0 +1,49 @@
+/*
+ gpgsetexpirytimeeditinteractor.h - Edit Interactor to change the expiry time of an OpenPGP key
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgSetExpiryTimeEditInteractor : public EditInteractor
+{
+public:
+ explicit GpgSetExpiryTimeEditInteractor(const std::string &timeString = "0");
+ ~GpgSetExpiryTimeEditInteractor();
+
+private:
+ /* reimp */ const char *action(Error &err) const;
+ /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+ const std::string m_strtime;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSETEXPIRYTIMEEDITINTERACTOR_H___
diff --git a/lang/cpp/src/gpgsetownertrusteditinteractor.cpp b/lang/cpp/src/gpgsetownertrusteditinteractor.cpp
new file mode 100644
index 0000000..15b1269
--- /dev/null
+++ b/lang/cpp/src/gpgsetownertrusteditinteractor.cpp
@@ -0,0 +1,151 @@
+/*
+ gpgsetownertrusteditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsetownertrusteditinteractor.h"
+#include "error.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+using namespace GpgME;
+
+GpgSetOwnerTrustEditInteractor::GpgSetOwnerTrustEditInteractor(Key::OwnerTrust ot)
+ : EditInteractor(),
+ m_ownertrust(ot)
+{
+
+}
+
+GpgSetOwnerTrustEditInteractor::~GpgSetOwnerTrustEditInteractor() {}
+
+// work around --enable-final
+namespace GpgSetOwnerTrustEditInteractor_Private
+{
+enum {
+ START = EditInteractor::StartState,
+ COMMAND,
+ VALUE,
+ REALLY_ULTIMATE,
+ QUIT,
+ SAVE,
+
+ ERROR = EditInteractor::ErrorState
+};
+}
+
+const char *GpgSetOwnerTrustEditInteractor::action(Error &err) const
+{
+ static const char truststrings[][2] = { "1", "1", "2", "3", "4", "5" };
+
+ using namespace GpgSetOwnerTrustEditInteractor_Private;
+
+ switch (state()) {
+ case COMMAND:
+ return "trust";
+ case VALUE:
+ return truststrings[m_ownertrust];
+ case REALLY_ULTIMATE:
+ return "Y";
+ case QUIT:
+ return "quit";
+ case SAVE:
+ return "Y";
+ case START:
+ case ERROR:
+ return 0;
+ default:
+ err = Error::fromCode(GPG_ERR_GENERAL);
+ return 0;
+ }
+}
+
+unsigned int GpgSetOwnerTrustEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+
+ static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+ //static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
+
+ if (needsNoResponse(status)) {
+ return state();
+ }
+
+ using namespace GpgSetOwnerTrustEditInteractor_Private;
+
+ switch (state()) {
+ case START:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return COMMAND;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case COMMAND:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "edit_ownertrust.value") == 0) {
+ return VALUE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case VALUE:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ } else if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0) {
+ return REALLY_ULTIMATE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case REALLY_ULTIMATE:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case QUIT:
+ if (status == GPGME_STATUS_GET_BOOL &&
+ strcmp(args, "keyedit.save.okay") == 0) {
+ return SAVE;
+ }
+ err = GENERAL_ERROR;
+ return ERROR;
+ case ERROR:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return QUIT;
+ }
+ err = lastError();
+ return ERROR;
+ default:
+ err = GENERAL_ERROR;
+ return ERROR;
+ };
+}
diff --git a/lang/cpp/src/gpgsetownertrusteditinteractor.h b/lang/cpp/src/gpgsetownertrusteditinteractor.h
new file mode 100644
index 0000000..caf29ee
--- /dev/null
+++ b/lang/cpp/src/gpgsetownertrusteditinteractor.h
@@ -0,0 +1,50 @@
+/*
+ gpgsetownertrusteditinteractor.h - Edit Interactor to change the owner trust of an OpenPGP key
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+#include <key.h>
+
+#include <string>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT GpgSetOwnerTrustEditInteractor : public EditInteractor
+{
+public:
+ explicit GpgSetOwnerTrustEditInteractor(Key::OwnerTrust ownertrust);
+ ~GpgSetOwnerTrustEditInteractor();
+
+private:
+ /* reimp */ const char *action(Error &err) const;
+ /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+ const Key::OwnerTrust m_ownertrust;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSETOWNERTRUSTEDITINTERACTOR_H__
diff --git a/lang/cpp/src/gpgsignkeyeditinteractor.cpp b/lang/cpp/src/gpgsignkeyeditinteractor.cpp
new file mode 100644
index 0000000..fded90f
--- /dev/null
+++ b/lang/cpp/src/gpgsignkeyeditinteractor.cpp
@@ -0,0 +1,318 @@
+/*
+ gpgsignkeyeditinteractor.cpp - Edit Interactor to change the expiry time of an OpenPGP key
+ Copyright (C) 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "gpgsignkeyeditinteractor.h"
+#include "error.h"
+#include "key.h"
+
+#include <gpgme.h>
+
+#include <map>
+#include <string>
+#include <sstream>
+
+#include <cassert>
+#include <cstring>
+
+using std::strcmp;
+
+// avoid conflict (msvc)
+#ifdef ERROR
+# undef ERROR
+#endif
+
+#ifdef _MSC_VER
+#undef snprintf
+#define snprintf _snprintf
+#endif
+
+using namespace GpgME;
+
+class GpgSignKeyEditInteractor::Private
+{
+public:
+ Private();
+
+ std::string scratch;
+ bool started;
+ int options;
+ std::vector<unsigned int> userIDs;
+ std::vector<unsigned int>::const_iterator currentId, nextId;
+ unsigned int checkLevel;
+
+ const char *command() const
+ {
+ const bool local = (options & Exportable) == 0;
+ const bool nonRevoc = options & NonRevocable;
+ const bool trust = options & Trust;
+ //TODO: check if all combinations are valid
+ if (local && nonRevoc && trust) {
+ return "ltnrsign";
+ }
+ if (local && nonRevoc) {
+ return "lnrsign";
+ }
+ if (local && trust) {
+ return "ltsign";
+ }
+ if (local) {
+ return "lsign";
+ }
+ if (nonRevoc && trust) {
+ return "tnrsign";
+ }
+ if (nonRevoc) {
+ return "nrsign";
+ }
+ if (trust) {
+ return "tsign";
+ }
+ return "sign";
+ }
+
+ bool signAll() const
+ {
+ return userIDs.empty();
+ }
+ unsigned int nextUserID()
+ {
+ assert(nextId != userIDs.end());
+ currentId = nextId++;
+ return currentUserID();
+ }
+
+ bool allUserIDsListed() const
+ {
+ return nextId == userIDs.end();
+ }
+
+ unsigned int currentUserID() const
+ {
+ assert(currentId != userIDs.end());
+ return *currentId + 1;
+ }
+
+};
+
+GpgSignKeyEditInteractor::Private::Private()
+ :
+ started(false),
+ options(0),
+ userIDs(),
+ currentId(),
+ nextId(),
+ checkLevel(0)
+{
+}
+
+GpgSignKeyEditInteractor::GpgSignKeyEditInteractor()
+ : EditInteractor(), d(new Private)
+{
+
+}
+
+GpgSignKeyEditInteractor::~GpgSignKeyEditInteractor()
+{
+ delete d;
+}
+
+// work around --enable-final
+namespace GpgSignKeyEditInteractor_Private
+{
+enum SignKeyState {
+ START = EditInteractor::StartState,
+ COMMAND,
+ UIDS_ANSWER_SIGN_ALL,
+ UIDS_LIST_SEPARATELY,
+ // all these free slots belong to UIDS_LIST_SEPARATELY, too
+ // (we increase state() by one for each UID, so that action() is called)
+ UIDS_LIST_SEPARATELY_DONE = 1000000,
+ SET_EXPIRE,
+ SET_CHECK_LEVEL,
+ SET_TRUST_VALUE,
+ SET_TRUST_DEPTH,
+ SET_TRUST_REGEXP,
+ CONFIRM,
+ QUIT,
+ SAVE,
+ ERROR = EditInteractor::ErrorState
+};
+
+typedef std::map<std::tuple<SignKeyState, unsigned int, std::string>, SignKeyState> TransitionMap;
+
+}
+
+static const char *answer(bool b)
+{
+ return b ? "Y" : "N";
+}
+
+static GpgSignKeyEditInteractor_Private::TransitionMap makeTable()
+{
+ using namespace GpgSignKeyEditInteractor_Private;
+ TransitionMap tab;
+ const unsigned int GET_BOOL = GPGME_STATUS_GET_BOOL;
+ const unsigned int GET_LINE = GPGME_STATUS_GET_LINE;
+#define addEntry( s1, status, str, s2 ) tab[std::make_tuple( s1, status, str)] = s2
+ addEntry(START, GET_LINE, "keyedit.prompt", COMMAND);
+ addEntry(COMMAND, GET_BOOL, "keyedit.sign_all.okay", UIDS_ANSWER_SIGN_ALL);
+ addEntry(COMMAND, GET_BOOL, "sign_uid.okay", CONFIRM);
+ addEntry(UIDS_ANSWER_SIGN_ALL, GET_BOOL, "sign_uid.okay", CONFIRM);
+ addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+ addEntry(UIDS_ANSWER_SIGN_ALL, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+ addEntry(SET_TRUST_VALUE, GET_LINE, "trustsign_prompt.trust_depth", SET_TRUST_DEPTH);
+ addEntry(SET_TRUST_DEPTH, GET_LINE, "trustsign_prompt.trust_regexp", SET_TRUST_REGEXP);
+ addEntry(SET_TRUST_REGEXP, GET_LINE, "sign_uid.okay", CONFIRM);
+ addEntry(SET_CHECK_LEVEL, GET_BOOL, "sign_uid.okay", CONFIRM);
+ addEntry(SET_EXPIRE, GET_BOOL, "sign_uid.class", SET_CHECK_LEVEL);
+ addEntry(CONFIRM, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
+ addEntry(CONFIRM, GET_BOOL, "sign_uid.okay", CONFIRM);
+ addEntry(CONFIRM, GET_LINE, "keyedit.prompt", COMMAND);
+ addEntry(CONFIRM, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
+ addEntry(CONFIRM, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+ addEntry(CONFIRM, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.local_promote_okay", CONFIRM);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "keyedit.prompt", COMMAND);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "trustsign_prompt.trust_value", SET_TRUST_VALUE);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.expire", SET_EXPIRE);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_LINE, "sign_uid.class", SET_CHECK_LEVEL);
+ addEntry(UIDS_LIST_SEPARATELY_DONE, GET_BOOL, "sign_uid.okay", CONFIRM);
+ addEntry(CONFIRM, GET_LINE, "keyedit.prompt", QUIT);
+ addEntry(ERROR, GET_LINE, "keyedit.prompt", QUIT);
+ addEntry(QUIT, GET_BOOL, "keyedit.save.okay", SAVE);
+#undef addEntry
+ return tab;
+}
+
+const char *GpgSignKeyEditInteractor::action(Error &err) const
+{
+ static const char check_level_strings[][2] = { "0", "1", "2", "3" };
+ using namespace GpgSignKeyEditInteractor_Private;
+ using namespace std;
+
+ switch (const unsigned int st = state()) {
+ case COMMAND:
+ return d->command();
+ case UIDS_ANSWER_SIGN_ALL:
+ return answer(d->signAll());
+ case UIDS_LIST_SEPARATELY_DONE:
+ return d->command();
+ case SET_EXPIRE:
+ return answer(true);
+ case SET_TRUST_VALUE:
+ // TODO
+ case SET_TRUST_DEPTH:
+ //TODO
+ case SET_TRUST_REGEXP:
+ //TODO
+ return 0;
+ case SET_CHECK_LEVEL:
+ return check_level_strings[d->checkLevel];
+ case CONFIRM:
+ return answer(true);
+ case QUIT:
+ return "quit";
+ case SAVE:
+ return answer(true);
+ default:
+ if (st >= UIDS_LIST_SEPARATELY && st < UIDS_LIST_SEPARATELY_DONE) {
+ std::stringstream ss;
+ ss << d->nextUserID();
+ d->scratch = ss.str();
+ return d->scratch.c_str();
+ }
+ // fall through
+ case ERROR:
+ err = Error::fromCode(GPG_ERR_GENERAL);
+ return 0;
+ }
+}
+
+unsigned int GpgSignKeyEditInteractor::nextState(unsigned int status, const char *args, Error &err) const
+{
+ d->started = true;
+ using namespace GpgSignKeyEditInteractor_Private;
+ static const Error GENERAL_ERROR = Error::fromCode(GPG_ERR_GENERAL);
+ //static const Error INV_TIME_ERROR = Error::fromCode( GPG_ERR_INV_TIME );
+ static const TransitionMap table(makeTable());
+ if (needsNoResponse(status)) {
+ return state();
+ }
+
+ using namespace GpgSignKeyEditInteractor_Private;
+
+ //lookup transition in map
+ const TransitionMap::const_iterator it = table.find(std::make_tuple(static_cast<SignKeyState>(state()), status, std::string(args)));
+ if (it != table.end()) {
+ return it->second;
+ }
+
+ //handle cases that cannot be handled via the map
+ switch (const unsigned int st = state()) {
+ case UIDS_ANSWER_SIGN_ALL:
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ if (!d->signAll()) {
+ return UIDS_LIST_SEPARATELY;
+ }
+ err = Error::fromCode(GPG_ERR_UNUSABLE_PUBKEY);
+ return ERROR;
+ }
+ break;
+ default:
+ if (st >= UIDS_LIST_SEPARATELY && st < UIDS_LIST_SEPARATELY_DONE) {
+ if (status == GPGME_STATUS_GET_LINE &&
+ strcmp(args, "keyedit.prompt") == 0) {
+ return d->allUserIDsListed() ? UIDS_LIST_SEPARATELY_DONE : st + 1 ;
+ }
+ }
+ break;
+ case CONFIRM:
+ case ERROR:
+ err = lastError();
+ return ERROR;
+ }
+
+ err = GENERAL_ERROR;
+ return ERROR;
+}
+
+void GpgSignKeyEditInteractor::setCheckLevel(unsigned int checkLevel)
+{
+ assert(!d->started);
+ assert(checkLevel <= 3);
+ d->checkLevel = checkLevel;
+}
+
+void GpgSignKeyEditInteractor::setUserIDsToSign(const std::vector<unsigned int> &userIDsToSign)
+{
+ assert(!d->started);
+ d->userIDs = userIDsToSign;
+ d->nextId = d->userIDs.begin();
+ d->currentId = d->userIDs.end();
+
+}
+void GpgSignKeyEditInteractor::setSigningOptions(int options)
+{
+ assert(!d->started);
+ d->options = options;
+}
diff --git a/lang/cpp/src/gpgsignkeyeditinteractor.h b/lang/cpp/src/gpgsignkeyeditinteractor.h
new file mode 100644
index 0000000..47ff8e5
--- /dev/null
+++ b/lang/cpp/src/gpgsignkeyeditinteractor.h
@@ -0,0 +1,64 @@
+/*
+ gpgsignkeyeditinteractor.h - Edit Interactor to change the owner trust of an OpenPGP key
+ Copyright (C) 2008 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
+#define __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
+
+#include <editinteractor.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class Key;
+class UserID;
+
+class GPGMEPP_EXPORT GpgSignKeyEditInteractor : public EditInteractor
+{
+public:
+ enum SignOption {
+ Exportable = 0x1,
+ NonRevocable = 0x2,
+ Trust = 0x4
+ };
+
+ GpgSignKeyEditInteractor();
+ ~GpgSignKeyEditInteractor();
+
+ void setCheckLevel(unsigned int checkLevel);
+ void setUserIDsToSign(const std::vector<unsigned int> &userIDsToSign);
+ void setSigningOptions(int options);
+
+private:
+ /* reimp */ const char *action(Error &err) const;
+ /* reimp */ unsigned int nextState(unsigned int statusCode, const char *args, Error &err) const;
+
+private:
+ class Private;
+ Private *const d;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_GPGSIGNKEYEDITINTERACTOR_H__
diff --git a/lang/cpp/src/importresult.cpp b/lang/cpp/src/importresult.cpp
new file mode 100644
index 0000000..97e8239
--- /dev/null
+++ b/lang/cpp/src/importresult.cpp
@@ -0,0 +1,215 @@
+/*
+ importresult.cpp - wraps a gpgme import result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include <importresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+#include <cstdlib>
+#include <cstring>
+
+#include <string.h>
+
+class GpgME::ImportResult::Private
+{
+public:
+ Private(const _gpgme_op_import_result &r) : res(r)
+ {
+ // copy recursively, using compiler-generated copy ctor.
+ // We just need to handle the pointers in the structs:
+ for (gpgme_import_status_t is = r.imports ; is ; is = is->next) {
+ gpgme_import_status_t copy = new _gpgme_import_status(*is);
+ copy->fpr = strdup(is->fpr);
+ copy->next = 0;
+ imports.push_back(copy);
+ }
+ res.imports = 0;
+ }
+ ~Private()
+ {
+ for (std::vector<gpgme_import_status_t>::iterator it = imports.begin() ; it != imports.end() ; ++it) {
+ std::free((*it)->fpr);
+ delete *it; *it = 0;
+ }
+ }
+
+ _gpgme_op_import_result res;
+ std::vector<gpgme_import_status_t> imports;
+};
+
+GpgME::ImportResult::ImportResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::ImportResult::ImportResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::ImportResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_import_result_t res = gpgme_op_import_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(*res));
+}
+
+make_standard_stuff(ImportResult)
+
+int GpgME::ImportResult::numConsidered() const
+{
+ return d ? d->res.considered : 0 ;
+}
+
+int GpgME::ImportResult::numKeysWithoutUserID() const
+{
+ return d ? d->res.no_user_id : 0 ;
+}
+
+int GpgME::ImportResult::numImported() const
+{
+ return d ? d->res.imported : 0 ;
+}
+
+int GpgME::ImportResult::numRSAImported() const
+{
+ return d ? d->res.imported_rsa : 0 ;
+}
+
+int GpgME::ImportResult::numUnchanged() const
+{
+ return d ? d->res.unchanged : 0 ;
+}
+
+int GpgME::ImportResult::newUserIDs() const
+{
+ return d ? d->res.new_user_ids : 0 ;
+}
+
+int GpgME::ImportResult::newSubkeys() const
+{
+ return d ? d->res.new_sub_keys : 0 ;
+}
+
+int GpgME::ImportResult::newSignatures() const
+{
+ return d ? d->res.new_signatures : 0 ;
+}
+
+int GpgME::ImportResult::newRevocations() const
+{
+ return d ? d->res.new_revocations : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysConsidered() const
+{
+ return d ? d->res.secret_read : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysImported() const
+{
+ return d ? d->res.secret_imported : 0 ;
+}
+
+int GpgME::ImportResult::numSecretKeysUnchanged() const
+{
+ return d ? d->res.secret_unchanged : 0 ;
+}
+
+int GpgME::ImportResult::notImported() const
+{
+ return d ? d->res.not_imported : 0 ;
+}
+
+GpgME::Import GpgME::ImportResult::import(unsigned int idx) const
+{
+ return Import(d, idx);
+}
+
+std::vector<GpgME::Import> GpgME::ImportResult::imports() const
+{
+ if (!d) {
+ return std::vector<Import>();
+ }
+ std::vector<Import> result;
+ result.reserve(d->imports.size());
+ for (unsigned int i = 0 ; i < d->imports.size() ; ++i) {
+ result.push_back(Import(d, i));
+ }
+ return result;
+}
+
+GpgME::Import::Import(const std::shared_ptr<ImportResult::Private> &parent, unsigned int i)
+ : d(parent), idx(i)
+{
+
+}
+
+GpgME::Import::Import() : d(), idx(0) {}
+
+bool GpgME::Import::isNull() const
+{
+ return !d || idx >= d->imports.size() ;
+}
+
+const char *GpgME::Import::fingerprint() const
+{
+ return isNull() ? 0 : d->imports[idx]->fpr ;
+}
+
+GpgME::Error GpgME::Import::error() const
+{
+ return Error(isNull() ? 0 : d->imports[idx]->result);
+}
+
+GpgME::Import::Status GpgME::Import::status() const
+{
+ if (isNull()) {
+ return Unknown;
+ }
+ const unsigned int s = d->imports[idx]->status;
+ unsigned int result = Unknown;
+ if (s & GPGME_IMPORT_NEW) {
+ result |= NewKey;
+ }
+ if (s & GPGME_IMPORT_UID) {
+ result |= NewUserIDs;
+ }
+ if (s & GPGME_IMPORT_SIG) {
+ result |= NewSignatures;
+ }
+ if (s & GPGME_IMPORT_SUBKEY) {
+ result |= NewSubkeys;
+ }
+ if (s & GPGME_IMPORT_SECRET) {
+ result |= ContainedSecretKey;
+ }
+ return static_cast<Status>(result);
+}
diff --git a/lang/cpp/src/importresult.h b/lang/cpp/src/importresult.h
new file mode 100644
index 0000000..adda80a
--- /dev/null
+++ b/lang/cpp/src/importresult.h
@@ -0,0 +1,134 @@
+/*
+ importresult.h - wraps a gpgme import result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_IMPORTRESULT_H__
+#define __GPGMEPP_IMPORTRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+#include <vector>
+
+namespace GpgME
+{
+
+class Error;
+class Import;
+
+class GPGMEPP_EXPORT ImportResult : public Result
+{
+public:
+ ImportResult();
+ ImportResult(gpgme_ctx_t ctx, int error);
+ ImportResult(gpgme_ctx_t ctx, const Error &error);
+ explicit ImportResult(const Error &error);
+
+ const ImportResult &operator=(ImportResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(ImportResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ int numConsidered() const;
+ int numKeysWithoutUserID() const;
+ int numImported() const;
+ int numRSAImported() const;
+ int numUnchanged() const;
+
+ int newUserIDs() const;
+ int newSubkeys() const;
+ int newSignatures() const;
+ int newRevocations() const;
+
+ int numSecretKeysConsidered() const;
+ int numSecretKeysImported() const;
+ int numSecretKeysUnchanged() const;
+
+ int notImported() const;
+
+ Import import(unsigned int idx) const;
+ std::vector<Import> imports() const;
+
+ class Private;
+private:
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+class GPGMEPP_EXPORT Import
+{
+ friend class ::GpgME::ImportResult;
+ Import(const std::shared_ptr<ImportResult::Private> &parent, unsigned int idx);
+public:
+ Import();
+
+ const Import &operator=(Import other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Import &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ swap(this->idx, other.idx);
+ }
+
+ bool isNull() const;
+
+ const char *fingerprint() const;
+ Error error() const;
+
+ enum Status {
+ Unknown = 0x0,
+ NewKey = 0x1,
+ NewUserIDs = 0x2,
+ NewSignatures = 0x4,
+ NewSubkeys = 0x8,
+ ContainedSecretKey = 0x10
+ };
+ Status status() const;
+
+private:
+ std::shared_ptr<ImportResult::Private> d;
+ unsigned int idx;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(ImportResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Import)
+
+#endif // __GPGMEPP_IMPORTRESULT_H__
diff --git a/lang/cpp/src/interfaces/assuantransaction.h b/lang/cpp/src/interfaces/assuantransaction.h
new file mode 100644
index 0000000..a382b05
--- /dev/null
+++ b/lang/cpp/src/interfaces/assuantransaction.h
@@ -0,0 +1,49 @@
+/*
+ assuantransaction.h - Interface for ASSUAN transactions
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB <info@kdab.com>
+ Author: Marc Mutz <marc@kdab.com>
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
+#define __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
+
+#include "gpgmepp_export.h"
+
+#include <stddef.h>
+
+namespace GpgME
+{
+
+class Error;
+class Data;
+
+class GPGMEPP_EXPORT AssuanTransaction
+{
+public:
+ virtual ~AssuanTransaction() {}
+
+ virtual Error data(const char *data, size_t datalen) = 0;
+ virtual Data inquire(const char *name, const char *args, Error &err) = 0;
+ virtual Error status(const char *status, const char *args) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_ASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/interfaces/dataprovider.h b/lang/cpp/src/interfaces/dataprovider.h
new file mode 100644
index 0000000..166bb4e
--- /dev/null
+++ b/lang/cpp/src/interfaces/dataprovider.h
@@ -0,0 +1,53 @@
+/*
+ interface/dataprovider.h - Interface for data sources
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_DATAPROVIDER_H__
+#define __GPGMEPP_INTERFACES_DATAPROVIDER_H__
+
+#include <sys/types.h>
+
+#include "gpgmepp_export.h"
+
+#include <gpg-error.h>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT DataProvider
+{
+public:
+ virtual ~DataProvider() {}
+
+ enum Operation {
+ Read, Write, Seek, Release
+ };
+ virtual bool isSupported(Operation op) const = 0;
+
+ virtual ssize_t read(void *buffer, size_t bufSize) = 0;
+ virtual ssize_t write(const void *buffer, size_t bufSize) = 0;
+ virtual off_t seek(off_t offset, int whence) = 0;
+ virtual void release() = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_DATAPROVIDER_H__
diff --git a/lang/cpp/src/interfaces/passphraseprovider.h b/lang/cpp/src/interfaces/passphraseprovider.h
new file mode 100644
index 0000000..5275e44
--- /dev/null
+++ b/lang/cpp/src/interfaces/passphraseprovider.h
@@ -0,0 +1,40 @@
+/*
+ interface/passphraseprovider.h - Interface for passphrase callbacks
+ Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
+#define __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
+
+namespace GpgME
+{
+
+class PassphraseProvider
+{
+public:
+ virtual ~PassphraseProvider() {}
+
+ virtual char *getPassphrase(const char *useridHint, const char *description,
+ bool previousWasBad, bool &canceled) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_PASSPHRASEPROVIDER_H__
diff --git a/lang/cpp/src/interfaces/progressprovider.h b/lang/cpp/src/interfaces/progressprovider.h
new file mode 100644
index 0000000..78bbdd7
--- /dev/null
+++ b/lang/cpp/src/interfaces/progressprovider.h
@@ -0,0 +1,40 @@
+/*
+ interface/progressprovider.h - Interface for progress reports
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
+#define __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
+
+namespace GpgME
+{
+
+class ProgressProvider
+{
+public:
+ virtual ~ProgressProvider() {}
+
+ virtual void showProgress(const char *what, int type,
+ int current, int total) = 0;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_INTERFACES_PROGRESSPROVIDER_H__
diff --git a/lang/cpp/src/key.cpp b/lang/cpp/src/key.cpp
new file mode 100644
index 0000000..cfa1ba3
--- /dev/null
+++ b/lang/cpp/src/key.cpp
@@ -0,0 +1,912 @@
+/*
+ key.cpp - wraps a gpgme key
+ Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <key.h>
+
+#include "util.h"
+#include "tofuinfo.h"
+#include "context.h"
+
+#include <gpgme.h>
+
+#include <string.h>
+#include <istream>
+#include <iterator>
+
+const GpgME::Key::Null GpgME::Key::null;
+
+namespace GpgME
+{
+
+Key::Key() : key() {}
+
+Key::Key(const Null &) : key() {}
+
+Key::Key(const shared_gpgme_key_t &k) : key(k) {}
+
+Key::Key(gpgme_key_t k, bool ref)
+ : key(k
+ ? shared_gpgme_key_t(k, &gpgme_key_unref)
+ : shared_gpgme_key_t())
+{
+ if (ref && impl()) {
+ gpgme_key_ref(impl());
+ }
+}
+
+UserID Key::userID(unsigned int index) const
+{
+ return UserID(key, index);
+}
+
+Subkey Key::subkey(unsigned int index) const
+{
+ return Subkey(key, index);
+}
+
+unsigned int Key::numUserIDs() const
+{
+ if (!key) {
+ return 0;
+ }
+ unsigned int count = 0;
+ for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
+ ++count;
+ }
+ return count;
+}
+
+unsigned int Key::numSubkeys() const
+{
+ if (!key) {
+ return 0;
+ }
+ unsigned int count = 0;
+ for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
+ ++count;
+ }
+ return count;
+}
+
+std::vector<UserID> Key::userIDs() const
+{
+ if (!key) {
+ return std::vector<UserID>();
+ }
+
+ std::vector<UserID> v;
+ v.reserve(numUserIDs());
+ for (gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next) {
+ v.push_back(UserID(key, uid));
+ }
+ return v;
+}
+
+std::vector<Subkey> Key::subkeys() const
+{
+ if (!key) {
+ return std::vector<Subkey>();
+ }
+
+ std::vector<Subkey> v;
+ v.reserve(numSubkeys());
+ for (gpgme_sub_key_t subkey = key->subkeys ; subkey ; subkey = subkey->next) {
+ v.push_back(Subkey(key, subkey));
+ }
+ return v;
+}
+
+Key::OwnerTrust Key::ownerTrust() const
+{
+ if (!key) {
+ return Unknown;
+ }
+ switch (key->owner_trust) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return Unknown;
+ case GPGME_VALIDITY_UNDEFINED: return Undefined;
+ case GPGME_VALIDITY_NEVER: return Never;
+ case GPGME_VALIDITY_MARGINAL: return Marginal;
+ case GPGME_VALIDITY_FULL: return Full;
+ case GPGME_VALIDITY_ULTIMATE: return Ultimate;
+ }
+}
+char Key::ownerTrustAsString() const
+{
+ if (!key) {
+ return '?';
+ }
+ switch (key->owner_trust) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return '?';
+ case GPGME_VALIDITY_UNDEFINED: return 'q';
+ case GPGME_VALIDITY_NEVER: return 'n';
+ case GPGME_VALIDITY_MARGINAL: return 'm';
+ case GPGME_VALIDITY_FULL: return 'f';
+ case GPGME_VALIDITY_ULTIMATE: return 'u';
+ }
+}
+
+Protocol Key::protocol() const
+{
+ if (!key) {
+ return UnknownProtocol;
+ }
+ switch (key->protocol) {
+ case GPGME_PROTOCOL_CMS: return CMS;
+ case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
+ default: return UnknownProtocol;
+ }
+}
+
+const char *Key::protocolAsString() const
+{
+ return key ? gpgme_get_protocol_name(key->protocol) : 0 ;
+}
+
+bool Key::isRevoked() const
+{
+ return key && key->revoked;
+}
+
+bool Key::isExpired() const
+{
+ return key && key->expired;
+}
+
+bool Key::isDisabled() const
+{
+ return key && key->disabled;
+}
+
+bool Key::isInvalid() const
+{
+ return key && key->invalid;
+}
+
+bool Key::hasSecret() const
+{
+ return key && key->secret;
+}
+
+bool Key::isRoot() const
+{
+ return key && key->subkeys && key->subkeys->fpr && key->chain_id &&
+ strcasecmp(key->subkeys->fpr, key->chain_id) == 0;
+}
+
+bool Key::canEncrypt() const
+{
+ return key && key->can_encrypt;
+}
+
+bool Key::canSign() const
+{
+#ifndef GPGME_CAN_SIGN_ON_SECRET_OPENPGP_KEYLISTING_NOT_BROKEN
+ if (key && key->protocol == GPGME_PROTOCOL_OpenPGP) {
+ return true;
+ }
+#endif
+ return canReallySign();
+}
+
+bool Key::canReallySign() const
+{
+ return key && key->can_sign;
+}
+
+bool Key::canCertify() const
+{
+ return key && key->can_certify;
+}
+
+bool Key::canAuthenticate() const
+{
+ return key && key->can_authenticate;
+}
+
+bool Key::isQualified() const
+{
+ return key && key->is_qualified;
+}
+
+const char *Key::issuerSerial() const
+{
+ return key ? key->issuer_serial : 0 ;
+}
+const char *Key::issuerName() const
+{
+ return key ? key->issuer_name : 0 ;
+}
+const char *Key::chainID() const
+{
+ return key ? key->chain_id : 0 ;
+}
+
+const char *Key::keyID() const
+{
+ return key && key->subkeys ? key->subkeys->keyid : 0 ;
+}
+
+const char *Key::shortKeyID() const
+{
+ if (!key || !key->subkeys || !key->subkeys->keyid) {
+ return 0;
+ }
+ const int len = strlen(key->subkeys->keyid);
+ if (len > 8) {
+ return key->subkeys->keyid + len - 8; // return the last 8 bytes (in hex notation)
+ } else {
+ return key->subkeys->keyid;
+ }
+}
+
+const char *Key::primaryFingerprint() const
+{
+ if (!key) {
+ return nullptr;
+ }
+ if (key->fpr) {
+ /* Return what gpgme thinks is the primary fingerprint */
+ return key->fpr;
+ }
+ if (key->subkeys) {
+ /* Return the first subkeys fingerprint */
+ return key->subkeys->fpr;
+ }
+}
+
+unsigned int Key::keyListMode() const
+{
+ return key ? convert_from_gpgme_keylist_mode_t(key->keylist_mode) : 0 ;
+}
+
+const Key &Key::mergeWith(const Key &other)
+{
+ // ### incomplete. Just merges has* and can*, nothing else atm
+ // ### detach also missing
+
+ if (!this->primaryFingerprint() ||
+ !other.primaryFingerprint() ||
+ strcasecmp(this->primaryFingerprint(), other.primaryFingerprint()) != 0) {
+ return *this; // only merge the Key object which describe the same key
+ }
+
+ const gpgme_key_t me = impl();
+ const gpgme_key_t him = other.impl();
+
+ if (!me || !him) {
+ return *this;
+ }
+
+ me->revoked |= him->revoked;
+ me->expired |= him->expired;
+ me->disabled |= him->disabled;
+ me->invalid |= him->invalid;
+ me->can_encrypt |= him->can_encrypt;
+ me->can_sign |= him->can_sign;
+ me->can_certify |= him->can_certify;
+ me->secret |= him->secret;
+ me->can_authenticate |= him->can_authenticate;
+ me->is_qualified |= him->is_qualified;
+ me->keylist_mode |= him->keylist_mode;
+
+ // make sure the gpgme_sub_key_t::is_cardkey flag isn't lost:
+ for (gpgme_sub_key_t mysk = me->subkeys ; mysk ; mysk = mysk->next) {
+ for (gpgme_sub_key_t hissk = him->subkeys ; hissk ; hissk = hissk->next) {
+ if (strcmp(mysk->fpr, hissk->fpr) == 0) {
+ mysk->is_cardkey |= hissk->is_cardkey;
+ break;
+ }
+ }
+ }
+
+ return *this;
+}
+
+void Key::update()
+{
+ auto ctx = Context::createForProtocol(protocol());
+ if (!ctx) {
+ return;
+ }
+ ctx->setKeyListMode(KeyListMode::Local |
+ KeyListMode::Signatures |
+ KeyListMode::SignatureNotations |
+ KeyListMode::Validate |
+ KeyListMode::WithTofu);
+ Error err;
+ auto newKey = ctx->key(primaryFingerprint(), err, hasSecret());
+ delete ctx;
+ if (err) {
+ return;
+ }
+ swap(newKey);
+ return;
+}
+
+//
+//
+// class Subkey
+//
+//
+
+gpgme_sub_key_t find_subkey(const shared_gpgme_key_t &key, unsigned int idx)
+{
+ if (key) {
+ for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next, --idx) {
+ if (idx == 0) {
+ return s;
+ }
+ }
+ }
+ return 0;
+}
+
+gpgme_sub_key_t verify_subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey)
+{
+ if (key) {
+ for (gpgme_sub_key_t s = key->subkeys ; s ; s = s->next) {
+ if (s == subkey) {
+ return subkey;
+ }
+ }
+ }
+ return 0;
+}
+
+Subkey::Subkey() : key(), subkey(0) {}
+
+Subkey::Subkey(const shared_gpgme_key_t &k, unsigned int idx)
+ : key(k), subkey(find_subkey(k, idx))
+{
+
+}
+
+Subkey::Subkey(const shared_gpgme_key_t &k, gpgme_sub_key_t sk)
+ : key(k), subkey(verify_subkey(k, sk))
+{
+
+}
+
+Key Subkey::parent() const
+{
+ return Key(key);
+}
+
+const char *Subkey::keyID() const
+{
+ return subkey ? subkey->keyid : 0 ;
+}
+
+const char *Subkey::fingerprint() const
+{
+ return subkey ? subkey->fpr : 0 ;
+}
+
+Subkey::PubkeyAlgo Subkey::publicKeyAlgorithm() const
+{
+ return subkey ? static_cast<PubkeyAlgo>(subkey->pubkey_algo) : AlgoUnknown;
+}
+
+const char *Subkey::publicKeyAlgorithmAsString() const
+{
+ return gpgme_pubkey_algo_name(subkey ? subkey->pubkey_algo : (gpgme_pubkey_algo_t)0);
+}
+
+/* static */
+const char *Subkey::publicKeyAlgorithmAsString(PubkeyAlgo algo)
+{
+ if (algo == AlgoUnknown) {
+ return NULL;
+ }
+ return gpgme_pubkey_algo_name(static_cast<gpgme_pubkey_algo_t>(algo));
+}
+
+std::string Subkey::algoName() const
+{
+ char *gpgmeStr;
+ if (subkey && (gpgmeStr = gpgme_pubkey_algo_string(subkey))) {
+ std::string ret = std::string(gpgmeStr);
+ gpgme_free(gpgmeStr);
+ return ret;
+ }
+ return std::string();
+}
+
+bool Subkey::canEncrypt() const
+{
+ return subkey && subkey->can_encrypt;
+}
+
+bool Subkey::canSign() const
+{
+ return subkey && subkey->can_sign;
+}
+
+bool Subkey::canCertify() const
+{
+ return subkey && subkey->can_certify;
+}
+
+bool Subkey::canAuthenticate() const
+{
+ return subkey && subkey->can_authenticate;
+}
+
+bool Subkey::isQualified() const
+{
+ return subkey && subkey->is_qualified;
+}
+
+bool Subkey::isCardKey() const
+{
+ return subkey && subkey->is_cardkey;
+}
+
+const char *Subkey::cardSerialNumber() const
+{
+ return subkey ? subkey->card_number : 0 ;
+}
+
+bool Subkey::isSecret() const
+{
+ return subkey && subkey->secret;
+}
+
+unsigned int Subkey::length() const
+{
+ return subkey ? subkey->length : 0 ;
+}
+
+time_t Subkey::creationTime() const
+{
+ return static_cast<time_t>(subkey ? subkey->timestamp : 0);
+}
+
+time_t Subkey::expirationTime() const
+{
+ return static_cast<time_t>(subkey ? subkey->expires : 0);
+}
+
+bool Subkey::neverExpires() const
+{
+ return expirationTime() == time_t(0);
+}
+
+bool Subkey::isRevoked() const
+{
+ return subkey && subkey->revoked;
+}
+
+bool Subkey::isInvalid() const
+{
+ return subkey && subkey->invalid;
+}
+
+bool Subkey::isExpired() const
+{
+ return subkey && subkey->expired;
+}
+
+bool Subkey::isDisabled() const
+{
+ return subkey && subkey->disabled;
+}
+
+//
+//
+// class UserID
+//
+//
+
+gpgme_user_id_t find_uid(const shared_gpgme_key_t &key, unsigned int idx)
+{
+ if (key) {
+ for (gpgme_user_id_t u = key->uids ; u ; u = u->next, --idx) {
+ if (idx == 0) {
+ return u;
+ }
+ }
+ }
+ return 0;
+}
+
+gpgme_user_id_t verify_uid(const shared_gpgme_key_t &key, gpgme_user_id_t uid)
+{
+ if (key) {
+ for (gpgme_user_id_t u = key->uids ; u ; u = u->next) {
+ if (u == uid) {
+ return uid;
+ }
+ }
+ }
+ return 0;
+}
+
+UserID::UserID() : key(), uid(0) {}
+
+UserID::UserID(const shared_gpgme_key_t &k, gpgme_user_id_t u)
+ : key(k), uid(verify_uid(k, u))
+{
+
+}
+
+UserID::UserID(const shared_gpgme_key_t &k, unsigned int idx)
+ : key(k), uid(find_uid(k, idx))
+{
+
+}
+
+Key UserID::parent() const
+{
+ return Key(key);
+}
+
+UserID::Signature UserID::signature(unsigned int index) const
+{
+ return Signature(key, uid, index);
+}
+
+unsigned int UserID::numSignatures() const
+{
+ if (!uid) {
+ return 0;
+ }
+ unsigned int count = 0;
+ for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
+ ++count;
+ }
+ return count;
+}
+
+std::vector<UserID::Signature> UserID::signatures() const
+{
+ if (!uid) {
+ return std::vector<Signature>();
+ }
+
+ std::vector<Signature> v;
+ v.reserve(numSignatures());
+ for (gpgme_key_sig_t sig = uid->signatures ; sig ; sig = sig->next) {
+ v.push_back(Signature(key, uid, sig));
+ }
+ return v;
+}
+
+const char *UserID::id() const
+{
+ return uid ? uid->uid : 0 ;
+}
+
+const char *UserID::name() const
+{
+ return uid ? uid->name : 0 ;
+}
+
+const char *UserID::email() const
+{
+ return uid ? uid->email : 0 ;
+}
+
+const char *UserID::comment() const
+{
+ return uid ? uid->comment : 0 ;
+}
+
+UserID::Validity UserID::validity() const
+{
+ if (!uid) {
+ return Unknown;
+ }
+ switch (uid->validity) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return Unknown;
+ case GPGME_VALIDITY_UNDEFINED: return Undefined;
+ case GPGME_VALIDITY_NEVER: return Never;
+ case GPGME_VALIDITY_MARGINAL: return Marginal;
+ case GPGME_VALIDITY_FULL: return Full;
+ case GPGME_VALIDITY_ULTIMATE: return Ultimate;
+ }
+}
+
+char UserID::validityAsString() const
+{
+ if (!uid) {
+ return '?';
+ }
+ switch (uid->validity) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return '?';
+ case GPGME_VALIDITY_UNDEFINED: return 'q';
+ case GPGME_VALIDITY_NEVER: return 'n';
+ case GPGME_VALIDITY_MARGINAL: return 'm';
+ case GPGME_VALIDITY_FULL: return 'f';
+ case GPGME_VALIDITY_ULTIMATE: return 'u';
+ }
+}
+
+bool UserID::isRevoked() const
+{
+ return uid && uid->revoked;
+}
+
+bool UserID::isInvalid() const
+{
+ return uid && uid->invalid;
+}
+
+TofuInfo UserID::tofuInfo() const
+{
+ if (!uid) {
+ return TofuInfo();
+ }
+ return TofuInfo(uid->tofu);
+}
+
+//
+//
+// class Signature
+//
+//
+
+gpgme_key_sig_t find_signature(gpgme_user_id_t uid, unsigned int idx)
+{
+ if (uid) {
+ for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next, --idx) {
+ if (idx == 0) {
+ return s;
+ }
+ }
+ }
+ return 0;
+}
+
+gpgme_key_sig_t verify_signature(gpgme_user_id_t uid, gpgme_key_sig_t sig)
+{
+ if (uid) {
+ for (gpgme_key_sig_t s = uid->signatures ; s ; s = s->next) {
+ if (s == sig) {
+ return sig;
+ }
+ }
+ }
+ return 0;
+}
+
+UserID::Signature::Signature() : key(), uid(0), sig(0) {}
+
+UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, unsigned int idx)
+ : key(k), uid(verify_uid(k, u)), sig(find_signature(uid, idx))
+{
+
+}
+
+UserID::Signature::Signature(const shared_gpgme_key_t &k, gpgme_user_id_t u, gpgme_key_sig_t s)
+ : key(k), uid(verify_uid(k, u)), sig(verify_signature(uid, s))
+{
+
+}
+
+UserID UserID::Signature::parent() const
+{
+ return UserID(key, uid);
+}
+
+const char *UserID::Signature::signerKeyID() const
+{
+ return sig ? sig->keyid : 0 ;
+}
+
+const char *UserID::Signature::algorithmAsString() const
+{
+ return gpgme_pubkey_algo_name(sig ? sig->pubkey_algo : (gpgme_pubkey_algo_t)0);
+}
+
+unsigned int UserID::Signature::algorithm() const
+{
+ return sig ? sig->pubkey_algo : 0 ;
+}
+
+time_t UserID::Signature::creationTime() const
+{
+ return static_cast<time_t>(sig ? sig->timestamp : 0);
+}
+
+time_t UserID::Signature::expirationTime() const
+{
+ return static_cast<time_t>(sig ? sig->expires : 0);
+}
+
+bool UserID::Signature::neverExpires() const
+{
+ return expirationTime() == time_t(0);
+}
+
+bool UserID::Signature::isRevokation() const
+{
+ return sig && sig->revoked;
+}
+
+bool UserID::Signature::isInvalid() const
+{
+ return sig && sig->invalid;
+}
+
+bool UserID::Signature::isExpired() const
+{
+ return sig && sig->expired;
+}
+
+bool UserID::Signature::isExportable() const
+{
+ return sig && sig->exportable;
+}
+
+const char *UserID::Signature::signerUserID() const
+{
+ return sig ? sig->uid : 0 ;
+}
+
+const char *UserID::Signature::signerName() const
+{
+ return sig ? sig->name : 0 ;
+}
+
+const char *UserID::Signature::signerEmail() const
+{
+ return sig ? sig->email : 0 ;
+}
+
+const char *UserID::Signature::signerComment() const
+{
+ return sig ? sig->comment : 0 ;
+}
+
+unsigned int UserID::Signature::certClass() const
+{
+ return sig ? sig->sig_class : 0 ;
+}
+
+UserID::Signature::Status UserID::Signature::status() const
+{
+ if (!sig) {
+ return GeneralError;
+ }
+
+ switch (gpgme_err_code(sig->status)) {
+ case GPG_ERR_NO_ERROR: return NoError;
+ case GPG_ERR_SIG_EXPIRED: return SigExpired;
+ case GPG_ERR_KEY_EXPIRED: return KeyExpired;
+ case GPG_ERR_BAD_SIGNATURE: return BadSignature;
+ case GPG_ERR_NO_PUBKEY: return NoPublicKey;
+ default:
+ case GPG_ERR_GENERAL: return GeneralError;
+ }
+}
+
+std::string UserID::Signature::statusAsString() const
+{
+ if (!sig) {
+ return std::string();
+ }
+ char buf[ 1024 ];
+ gpgme_strerror_r(sig->status, buf, sizeof buf);
+ buf[ sizeof buf - 1 ] = '\0';
+ return std::string(buf);
+}
+
+GpgME::Notation UserID::Signature::notation(unsigned int idx) const
+{
+ if (!sig) {
+ return GpgME::Notation();
+ }
+ for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+ if (nota->name) {
+ if (idx-- == 0) {
+ return GpgME::Notation(nota);
+ }
+ }
+ }
+ return GpgME::Notation();
+}
+
+unsigned int UserID::Signature::numNotations() const
+{
+ if (!sig) {
+ return 0;
+ }
+ unsigned int count = 0;
+ for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+ if (nota->name) {
+ ++count; // others are policy URLs...
+ }
+ }
+ return count;
+}
+
+std::vector<Notation> UserID::Signature::notations() const
+{
+ if (!sig) {
+ return std::vector<GpgME::Notation>();
+ }
+ std::vector<GpgME::Notation> v;
+ v.reserve(numNotations());
+ for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+ if (nota->name) {
+ v.push_back(GpgME::Notation(nota));
+ }
+ }
+ return v;
+}
+
+const char *UserID::Signature::policyURL() const
+{
+ if (!sig) {
+ return 0;
+ }
+ for (gpgme_sig_notation_t nota = sig->notations ; nota ; nota = nota->next) {
+ if (!nota->name) {
+ return nota->value;
+ }
+ }
+ return 0;
+}
+
+std::ostream &operator<<(std::ostream &os, const UserID &uid)
+{
+ os << "GpgME::UserID(";
+ if (!uid.isNull()) {
+ os << "\n name: " << protect(uid.name())
+ << "\n email: " << protect(uid.email())
+ << "\n comment: " << protect(uid.comment())
+ << "\n validity: " << uid.validityAsString()
+ << "\n revoked: " << uid.isRevoked()
+ << "\n invalid: " << uid.isInvalid()
+ << "\n numsigs: " << uid.numSignatures()
+ << "\n tofuinfo:\n" << uid.tofuInfo();
+ }
+ return os << ')';
+}
+
+std::ostream &operator<<(std::ostream &os, const Key &key)
+{
+ os << "GpgME::Key(";
+ if (!key.isNull()) {
+ os << "\n protocol: " << protect(key.protocolAsString())
+ << "\n ownertrust: " << key.ownerTrustAsString()
+ << "\n issuer: " << protect(key.issuerName())
+ << "\n fingerprint:" << protect(key.primaryFingerprint())
+ << "\n listmode: " << key.keyListMode()
+ << "\n canSign: " << key.canReallySign()
+ << "\n canEncrypt: " << key.canEncrypt()
+ << "\n canCertify: " << key.canCertify()
+ << "\n canAuth: " << key.canAuthenticate()
+ << "\n uids:\n";
+ const std::vector<UserID> uids = key.userIDs();
+ std::copy(uids.begin(), uids.end(),
+ std::ostream_iterator<UserID>(os, "\n"));
+ }
+ return os << ')';
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/key.h b/lang/cpp/src/key.h
new file mode 100644
index 0000000..f193093
--- /dev/null
+++ b/lang/cpp/src/key.h
@@ -0,0 +1,415 @@
+/*
+ key.h - wraps a gpgme key
+ Copyright (C) 2003, 2005 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_KEY_H__
+#define __GPGMEPP_KEY_H__
+
+#include "global.h"
+#include "notation.h"
+
+#include "gpgmefw.h"
+
+#include <memory>
+#include <sys/time.h>
+
+#include <vector>
+#include <algorithm>
+#include <string>
+
+namespace GpgME
+{
+
+class Context;
+
+class Subkey;
+class UserID;
+class TofuInfo;
+
+typedef std::shared_ptr< std::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
+
+//
+// class Key
+//
+
+class GPGMEPP_EXPORT Key
+{
+ friend class ::GpgME::Context;
+ struct Null {
+ Null() {}
+ };
+public:
+ Key();
+ /* implicit */ Key(const Null &);
+ Key(const shared_gpgme_key_t &key);
+ Key(gpgme_key_t key, bool acquireRef);
+
+ static const Null null;
+
+ const Key &operator=(Key other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ const Key &mergeWith(const Key &other);
+
+ void swap(Key &other)
+ {
+ using std::swap;
+ swap(this->key, other.key);
+ }
+
+ bool isNull() const
+ {
+ return !key;
+ }
+
+ UserID userID(unsigned int index) const;
+ Subkey subkey(unsigned int index) const;
+
+ unsigned int numUserIDs() const;
+ unsigned int numSubkeys() const;
+
+ std::vector<UserID> userIDs() const;
+ std::vector<Subkey> subkeys() const;
+
+ bool isRevoked() const;
+ bool isExpired() const;
+ bool isDisabled() const;
+ bool isInvalid() const;
+
+ bool canEncrypt() const;
+ /*!
+ This function contains a workaround for old gpgme's: all secret
+ OpenPGP keys canSign() == true, which canReallySign() doesn't
+ have. I don't have time to find what breaks when I remove this
+ workaround, but since Kleopatra merges secret into public keys,
+ the workaround is not necessary there (and actively harms), I've
+ added a new function instead.
+ */
+ bool canSign() const;
+ bool canReallySign() const;
+ bool canCertify() const;
+ bool canAuthenticate() const;
+ bool isQualified() const;
+
+ bool hasSecret() const;
+ GPGMEPP_DEPRECATED bool isSecret() const
+ {
+ return hasSecret();
+ }
+
+ /*!
+ @return true if this is a X.509 root certificate (currently
+ equivalent to something like
+ strcmp( chainID(), subkey(0).fingerprint() ) == 0 )
+ */
+ bool isRoot() const;
+
+ enum OwnerTrust { Unknown = 0, Undefined = 1, Never = 2,
+ Marginal = 3, Full = 4, Ultimate = 5
+ };
+
+ OwnerTrust ownerTrust() const;
+ char ownerTrustAsString() const;
+
+ Protocol protocol() const;
+ const char *protocolAsString() const;
+
+ const char *issuerSerial() const;
+ const char *issuerName() const;
+ const char *chainID() const;
+
+ const char *keyID() const;
+ const char *shortKeyID() const;
+ const char *primaryFingerprint() const;
+
+ unsigned int keyListMode() const;
+
+ /*! Update information about this key.
+ * Starts a keylisting for this key with validity
+ * and tofu information gathering. Blocks for
+ * how long the keylisting takes.*/
+ void update();
+
+private:
+ gpgme_key_t impl() const
+ {
+ return key.get();
+ }
+ shared_gpgme_key_t key;
+};
+
+//
+// class Subkey
+//
+
+class GPGMEPP_EXPORT Subkey
+{
+public:
+ Subkey();
+ Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
+ Subkey(const shared_gpgme_key_t &key, unsigned int idx);
+
+ const Subkey &operator=(Subkey other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Subkey &other)
+ {
+ using std::swap;
+ swap(this->key, other.key);
+ swap(this->subkey, other.subkey);
+ }
+
+ bool isNull() const
+ {
+ return !key || !subkey;
+ }
+
+ Key parent() const;
+
+ const char *keyID() const;
+ const char *fingerprint() const;
+
+ time_t creationTime() const;
+ time_t expirationTime() const;
+ bool neverExpires() const;
+
+ bool isRevoked() const;
+ bool isExpired() const;
+ bool isInvalid() const;
+ bool isDisabled() const;
+
+ bool canEncrypt() const;
+ bool canSign() const;
+ bool canCertify() const;
+ bool canAuthenticate() const;
+ bool isQualified() const;
+ bool isCardKey() const;
+
+ bool isSecret() const;
+
+ /** Same as gpgme_pubkey_algo_t */
+ enum PubkeyAlgo {
+ AlgoUnknown = 0,
+ AlgoRSA = 1,
+ AlgoRSA_E = 2,
+ AlgoRSA_S = 3,
+ AlgoELG_E = 16,
+ AlgoDSA = 17,
+ AlgoECC = 18,
+ AlgoELG = 20,
+ AlgoECDSA = 301,
+ AlgoECDH = 302,
+ AlgoEDDSA = 303,
+ AlgoMax = 1 << 31
+ };
+
+ PubkeyAlgo publicKeyAlgorithm() const;
+
+ /**
+ @brief Get the public key algorithm name.
+
+ This only works for the pre 2.1 algorithms for ECC NULL is returned.
+
+ @returns a statically allocated string with the name of the public
+ key algorithm, or NULL if that name is not known.
+ */
+ const char *publicKeyAlgorithmAsString() const;
+
+ /** @brief Same as publicKeyAlgorithmAsString but static. */
+ static const char *publicKeyAlgorithmAsString(PubkeyAlgo algo);
+
+ /**
+ @brief Get the key algo string like GnuPG 2.1 prints it.
+
+ This returns combinations of size and algorithm. Like
+ bp512 or rsa2048. Misnamed because publicKeyAlgorithmAsString
+ already used the older pubkey_algo_name.
+ Actually uses gpgme_pubkey_algo_string.
+
+ @returns the key algorithm as string. Empty string on error.
+ */
+ std::string algoName() const;
+
+ unsigned int length() const;
+
+ const char *cardSerialNumber() const;
+
+private:
+ shared_gpgme_key_t key;
+ gpgme_sub_key_t subkey;
+};
+
+//
+// class UserID
+//
+
+class GPGMEPP_EXPORT UserID
+{
+public:
+ class Signature;
+
+ UserID();
+ UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
+ UserID(const shared_gpgme_key_t &key, unsigned int idx);
+
+ const UserID &operator=(UserID other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(UserID &other)
+ {
+ using std::swap;
+ swap(this->key, other.key);
+ swap(this->uid, other.uid);
+ }
+
+ bool isNull() const
+ {
+ return !key || !uid;
+ }
+
+ Key parent() const;
+
+ unsigned int numSignatures() const;
+ Signature signature(unsigned int index) const;
+ std::vector<Signature> signatures() const;
+
+ const char *id() const;
+ const char *name() const;
+ const char *email() const;
+ const char *comment() const;
+
+ enum Validity { Unknown = 0, Undefined = 1, Never = 2,
+ Marginal = 3, Full = 4, Ultimate = 5
+ };
+
+ Validity validity() const;
+ char validityAsString() const;
+
+ bool isRevoked() const;
+ bool isInvalid() const;
+
+ /** TOFU info for this userid.
+ * @returns The TOFU stats or a null TofuInfo.
+ */
+ GpgME::TofuInfo tofuInfo() const;
+private:
+ shared_gpgme_key_t key;
+ gpgme_user_id_t uid;
+};
+
+//
+// class UserID::Signature
+//
+
+class GPGMEPP_EXPORT UserID::Signature
+{
+public:
+ typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
+
+ Signature();
+ Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
+ Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
+
+ const Signature &operator=(Signature other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Signature &other)
+ {
+ using std::swap;
+ swap(this->key, other.key);
+ swap(this->uid, other.uid);
+ swap(this->sig, other.sig);
+ }
+
+ bool isNull() const
+ {
+ return !sig || !uid || !key ;
+ }
+
+ UserID parent() const;
+
+ const char *signerKeyID() const;
+
+ const char *algorithmAsString() const;
+ unsigned int algorithm() const;
+ time_t creationTime() const;
+ time_t expirationTime() const;
+ bool neverExpires() const;
+
+ bool isRevokation() const;
+ bool isInvalid() const;
+ bool isExpired() const;
+ bool isExportable() const;
+
+ const char *signerUserID() const;
+ const char *signerName() const;
+ const char *signerEmail() const;
+ const char *signerComment() const;
+
+ unsigned int certClass() const;
+
+ enum Status { NoError = 0, SigExpired, KeyExpired,
+ BadSignature, NoPublicKey, GeneralError
+ };
+ Status status() const;
+ std::string statusAsString() const;
+
+ const char *policyURL() const;
+
+ unsigned int numNotations() const;
+ GpgME::Notation notation(unsigned int idx) const;
+ std::vector<GpgME::Notation> notations() const;
+
+private:
+ shared_gpgme_key_t key;
+ gpgme_user_id_t uid;
+ gpgme_key_sig_t sig;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const UserID &uid);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Key &key);
+
+} // namespace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Key)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Subkey)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID::Signature)
+
+GPGMEPP_MAKE_STRCMP(ByFingerprint, .primaryFingerprint());
+GPGMEPP_MAKE_STRCMP(ByKeyID, .keyID());
+GPGMEPP_MAKE_STRCMP(ByShortKeyID, .shortKeyID());
+GPGMEPP_MAKE_STRCMP(ByChainID, .chainID());
+
+#endif // __GPGMEPP_KEY_H__
diff --git a/lang/cpp/src/keygenerationresult.cpp b/lang/cpp/src/keygenerationresult.cpp
new file mode 100644
index 0000000..7837e20
--- /dev/null
+++ b/lang/cpp/src/keygenerationresult.cpp
@@ -0,0 +1,92 @@
+/*
+ keygenerationresult.cpp - wraps a gpgme keygen result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <keygenerationresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+
+#include <string.h>
+
+class GpgME::KeyGenerationResult::Private
+{
+public:
+ Private(const _gpgme_op_genkey_result &r) : res(r)
+ {
+ if (res.fpr) {
+ res.fpr = strdup(res.fpr);
+ }
+ }
+ ~Private()
+ {
+ if (res.fpr) {
+ std::free(res.fpr);
+ }
+ res.fpr = 0;
+ }
+
+ _gpgme_op_genkey_result res;
+};
+
+GpgME::KeyGenerationResult::KeyGenerationResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::KeyGenerationResult::KeyGenerationResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::KeyGenerationResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_genkey_result_t res = gpgme_op_genkey_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(*res));
+}
+
+make_standard_stuff(KeyGenerationResult)
+
+bool GpgME::KeyGenerationResult::isPrimaryKeyGenerated() const
+{
+ return d && d->res.primary;
+}
+
+bool GpgME::KeyGenerationResult::isSubkeyGenerated() const
+{
+ return d && d->res.sub;
+}
+
+const char *GpgME::KeyGenerationResult::fingerprint() const
+{
+ return d ? d->res.fpr : 0 ;
+}
diff --git a/lang/cpp/src/keygenerationresult.h b/lang/cpp/src/keygenerationresult.h
new file mode 100644
index 0000000..c35c504
--- /dev/null
+++ b/lang/cpp/src/keygenerationresult.h
@@ -0,0 +1,82 @@
+/*
+ keygenerationresult.h - wraps a gpgme keygen result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_KEYGENERATIONRESULT_H__
+#define __GPGMEPP_KEYGENERATIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT KeyGenerationResult : public Result
+{
+public:
+ KeyGenerationResult();
+ KeyGenerationResult(gpgme_ctx_t ctx, int error);
+ KeyGenerationResult(gpgme_ctx_t ctx, const Error &error);
+ explicit KeyGenerationResult(const Error &err);
+
+ const KeyGenerationResult &operator=(KeyGenerationResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(KeyGenerationResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ GPGMEPP_DEPRECATED bool primaryKeyGenerated() const
+ {
+ return isPrimaryKeyGenerated();
+ }
+ GPGMEPP_DEPRECATED bool subkeyGenerated() const
+ {
+ return isSubkeyGenerated();
+ }
+ bool isPrimaryKeyGenerated() const;
+ bool isSubkeyGenerated() const;
+ const char *fingerprint() const;
+
+private:
+ class Private;
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(KeyGenerationResult)
+
+#endif // __GPGMEPP_KEYGENERATIONRESULT_H__
diff --git a/lang/cpp/src/keylistresult.cpp b/lang/cpp/src/keylistresult.cpp
new file mode 100644
index 0000000..4512d3b
--- /dev/null
+++ b/lang/cpp/src/keylistresult.cpp
@@ -0,0 +1,107 @@
+/*
+ keylistresult.cpp - wraps a gpgme keylist result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <keylistresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cassert>
+
+class GpgME::KeyListResult::Private
+{
+public:
+ Private(const _gpgme_op_keylist_result &r) : res(r) {}
+ Private(const Private &other) : res(other.res) {}
+
+ _gpgme_op_keylist_result res;
+};
+
+GpgME::KeyListResult::KeyListResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::KeyListResult::KeyListResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::KeyListResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_keylist_result_t res = gpgme_op_keylist_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(*res));
+}
+
+GpgME::KeyListResult::KeyListResult(const Error &error, const _gpgme_op_keylist_result &res)
+ : GpgME::Result(error), d(new Private(res))
+{
+
+}
+
+make_standard_stuff(KeyListResult)
+
+void GpgME::KeyListResult::detach()
+{
+ if (!d || d.unique()) {
+ return;
+ }
+ d.reset(new Private(*d));
+}
+
+void GpgME::KeyListResult::mergeWith(const KeyListResult &other)
+{
+ if (other.isNull()) {
+ return;
+ }
+ if (isNull()) { // just assign
+ operator=(other);
+ return;
+ }
+ // merge the truncated flag (try to keep detaching to a minimum):
+ if (other.isTruncated() && !this->isTruncated()) {
+ assert(other.d);
+ detach();
+ if (!d) {
+ d.reset(new Private(*other.d));
+ } else {
+ d->res.truncated = true;
+ }
+ }
+ if (! bool(error())) { // only merge the error when there was none yet.
+ Result::operator=(other);
+ }
+}
+
+bool GpgME::KeyListResult::isTruncated() const
+{
+ return d && d->res.truncated;
+}
diff --git a/lang/cpp/src/keylistresult.h b/lang/cpp/src/keylistresult.h
new file mode 100644
index 0000000..7dfe2d7
--- /dev/null
+++ b/lang/cpp/src/keylistresult.h
@@ -0,0 +1,81 @@
+/*
+ keylistresult.h - wraps a gpgme keylist result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_KEYLISTRESULT_H__
+#define __GPGMEPP_KEYLISTRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT KeyListResult : public Result
+{
+public:
+ KeyListResult();
+ KeyListResult(gpgme_ctx_t ctx, int error);
+ KeyListResult(gpgme_ctx_t ctx, const Error &error);
+ explicit KeyListResult(const Error &err);
+ KeyListResult(const Error &err, const _gpgme_op_keylist_result &res);
+
+ const KeyListResult &operator=(KeyListResult other)
+ {
+ swap(other);
+ return *this;
+ }
+ void swap(KeyListResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ const KeyListResult &operator+=(const KeyListResult &other)
+ {
+ mergeWith(other);
+ return *this;
+ }
+
+ void mergeWith(const KeyListResult &other);
+
+ bool isNull() const;
+
+ bool isTruncated() const;
+
+private:
+ void detach();
+ void init(gpgme_ctx_t ctx);
+ class Private;
+ std::shared_ptr<Private> d;
+};
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(KeyListResult)
+
+#endif // __GPGMEPP_KEYLISTRESULT_H__
diff --git a/lang/cpp/src/notation.h b/lang/cpp/src/notation.h
new file mode 100644
index 0000000..807bdaa
--- /dev/null
+++ b/lang/cpp/src/notation.h
@@ -0,0 +1,84 @@
+/*
+ notation.h - wraps a gpgme verify result
+ Copyright (C) 2004, 2007 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_NOTATION_H__
+#define __GPGMEPP_NOTATION_H__
+
+#include "gpgmefw.h"
+#include "verificationresult.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Notation
+{
+ friend class ::GpgME::Signature;
+ Notation(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex);
+public:
+ Notation();
+ explicit Notation(gpgme_sig_notation_t nota);
+
+ const Notation &operator=(Notation other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Notation &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ const char *name() const;
+ const char *value() const;
+
+ enum Flags {
+ NoFlags = 0,
+ HumanReadable = 1,
+ Critical = 2
+ };
+ Flags flags() const;
+
+ bool isHumanReadable() const;
+ bool isCritical() const;
+
+private:
+ class Private;
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Notation &nota);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Notation::Flags flags);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Notation)
+
+#endif // __GPGMEPP_NOTATION_H__
diff --git a/lang/cpp/src/result.h b/lang/cpp/src/result.h
new file mode 100644
index 0000000..a86d81f
--- /dev/null
+++ b/lang/cpp/src/result.h
@@ -0,0 +1,58 @@
+/*
+ result.h - base class for results
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_RESULT_H__
+#define __GPGMEPP_RESULT_H__
+
+#include "gpgmefw.h"
+#include "error.h"
+
+#include <algorithm> // std::swap
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT Result
+{
+protected:
+ explicit Result() : mError() {}
+ explicit Result(int err) : mError(err) {}
+ explicit Result(const Error &err) : mError(err) {}
+
+ void swap(Result &other)
+ {
+ std::swap(other.mError, mError);
+ }
+
+public:
+ const Error &error() const
+ {
+ return mError;
+ }
+
+protected:
+ Error mError;
+};
+
+}
+
+#endif // __GPGMEPP_RESULT_H__
diff --git a/lang/cpp/src/result_p.h b/lang/cpp/src/result_p.h
new file mode 100644
index 0000000..0cf73e4
--- /dev/null
+++ b/lang/cpp/src/result_p.h
@@ -0,0 +1,43 @@
+/*
+ result.h - base class for results
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_RESULT_P_H__
+#define __GPGMEPP_RESULT_P_H__
+
+#define make_default_ctor(x) \
+ GpgME::x::x() : GpgME::Result(), d() {}
+
+#define make_error_ctor(x) \
+ GpgME::x::x( const Error & error ) \
+ : GpgME::Result( error ), d() \
+ { \
+ \
+ }
+
+#define make_isNull(x) bool GpgME::x::isNull() const { return !d && !bool(error()); }
+
+#define make_standard_stuff(x) \
+ make_default_ctor(x) \
+ make_error_ctor(x) \
+ make_isNull(x)
+
+#endif // __GPGMEPP_RESULT_P_H__
diff --git a/lang/cpp/src/scdgetinfoassuantransaction.cpp b/lang/cpp/src/scdgetinfoassuantransaction.cpp
new file mode 100644
index 0000000..073d772
--- /dev/null
+++ b/lang/cpp/src/scdgetinfoassuantransaction.cpp
@@ -0,0 +1,156 @@
+/*
+ scdgetinfoassuantransaction.cpp - Assuan Transaction to get information from scdaemon
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "scdgetinfoassuantransaction.h"
+#include "error.h"
+#include "data.h"
+#include "util.h"
+
+#include <sstream>
+#include <assert.h>
+
+using namespace GpgME;
+
+ScdGetInfoAssuanTransaction::ScdGetInfoAssuanTransaction(InfoItem item)
+ : AssuanTransaction(),
+ m_item(item),
+ m_command(),
+ m_data()
+{
+
+}
+
+ScdGetInfoAssuanTransaction::~ScdGetInfoAssuanTransaction() {}
+
+static std::vector<std::string> to_reader_list(const std::string &s)
+{
+ std::vector<std::string> result;
+ std::stringstream ss(s);
+ std::string tok;
+ while (std::getline(ss, tok, '\n')) {
+ result.push_back(tok);
+ }
+ return result;
+}
+
+static std::vector<std::string> to_app_list(const std::string &s)
+{
+ return to_reader_list(s);
+}
+
+std::string ScdGetInfoAssuanTransaction::version() const
+{
+ if (m_item == Version) {
+ return m_data;
+ } else {
+ return std::string();
+ }
+}
+
+unsigned int ScdGetInfoAssuanTransaction::pid() const
+{
+ if (m_item == Pid) {
+ return to_pid(m_data);
+ } else {
+ return 0U;
+ }
+}
+
+std::string ScdGetInfoAssuanTransaction::socketName() const
+{
+ if (m_item == SocketName) {
+ return m_data;
+ } else {
+ return std::string();
+ }
+}
+
+char ScdGetInfoAssuanTransaction::status() const
+{
+ if (m_item == Status && !m_data.empty()) {
+ return m_data[0];
+ } else {
+ return '\0';
+ }
+}
+
+std::vector<std::string> ScdGetInfoAssuanTransaction::readerList() const
+{
+ if (m_item == ReaderList) {
+ return to_reader_list(m_data);
+ } else {
+ return std::vector<std::string>();
+ }
+}
+
+std::vector<std::string> ScdGetInfoAssuanTransaction::applicationList() const
+{
+ if (m_item == ApplicationList) {
+ return to_app_list(m_data);
+ } else {
+ return std::vector<std::string>();
+ }
+}
+
+static const char *const scd_getinfo_tokens[] = {
+ "version",
+ "pid",
+ "socket_name",
+ "status",
+ "reader_list",
+ "deny_admin",
+ "app_list",
+};
+static_assert((sizeof scd_getinfo_tokens / sizeof * scd_getinfo_tokens == ScdGetInfoAssuanTransaction::LastInfoItem),
+ "getinfo_tokens size mismatch");
+
+void ScdGetInfoAssuanTransaction::makeCommand() const
+{
+ assert(m_item >= 0);
+ assert(m_item < LastInfoItem);
+ m_command = "SCD GETINFO ";
+ m_command += scd_getinfo_tokens[m_item];
+}
+
+const char *ScdGetInfoAssuanTransaction::command() const
+{
+ makeCommand();
+ return m_command.c_str();
+}
+
+Error ScdGetInfoAssuanTransaction::data(const char *data, size_t len)
+{
+ m_data.append(data, len);
+ return Error();
+}
+
+Data ScdGetInfoAssuanTransaction::inquire(const char *name, const char *args, Error &err)
+{
+ (void)name; (void)args; (void)err;
+ return Data::null;
+}
+
+Error ScdGetInfoAssuanTransaction::status(const char *status, const char *args)
+{
+ (void)status; (void)args;
+ return Error();
+}
diff --git a/lang/cpp/src/scdgetinfoassuantransaction.h b/lang/cpp/src/scdgetinfoassuantransaction.h
new file mode 100644
index 0000000..a22a0ff
--- /dev/null
+++ b/lang/cpp/src/scdgetinfoassuantransaction.h
@@ -0,0 +1,76 @@
+/*
+ scdgetinfoassuantransaction.h - Assuan Transaction to get information from scdaemon
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
+#define __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
+
+#include <interfaces/assuantransaction.h>
+
+#include <string>
+#include <vector>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT ScdGetInfoAssuanTransaction : public AssuanTransaction
+{
+public:
+ enum InfoItem {
+ Version, // string
+ Pid, // unsigned long
+ SocketName, // string (path)
+ Status, // char (status)
+ ReaderList, // string list
+ DenyAdmin, // (none, returns GPG_ERR_GENERAL when admin commands are allowed)
+ ApplicationList, // string list
+
+ LastInfoItem
+ };
+
+ explicit ScdGetInfoAssuanTransaction(InfoItem item);
+ ~ScdGetInfoAssuanTransaction();
+
+ std::string version() const;
+ unsigned int pid() const;
+ std::string socketName() const;
+ char status() const;
+ std::vector<std::string> readerList() const;
+ std::vector<std::string> applicationList() const;
+
+private:
+ /* reimp */ const char *command() const;
+ /* reimp */ Error data(const char *data, size_t datalen);
+ /* reimp */ Data inquire(const char *name, const char *args, Error &err);
+ /* reimp */ Error status(const char *status, const char *args);
+
+private:
+ void makeCommand() const;
+
+private:
+ InfoItem m_item;
+ mutable std::string m_command;
+ std::string m_data;
+};
+
+} // namespace GpgME
+
+#endif // __GPGMEPP_SCDGETINFOASSUANTRANSACTION_H__
diff --git a/lang/cpp/src/signingresult.cpp b/lang/cpp/src/signingresult.cpp
new file mode 100644
index 0000000..4f2ef72
--- /dev/null
+++ b/lang/cpp/src/signingresult.cpp
@@ -0,0 +1,265 @@
+/*
+ signingresult.cpp - wraps a gpgme verify result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <signingresult.h>
+#include "result_p.h"
+#include "util.h"
+
+#include <gpgme.h>
+
+#include <cstring>
+#include <cstdlib>
+#include <algorithm>
+#include <istream>
+#include <iterator>
+
+#include <string.h>
+
+class GpgME::SigningResult::Private
+{
+public:
+ Private(const gpgme_sign_result_t r)
+ {
+ if (!r) {
+ return;
+ }
+ for (gpgme_new_signature_t is = r->signatures ; is ; is = is->next) {
+ gpgme_new_signature_t copy = new _gpgme_new_signature(*is);
+ if (is->fpr) {
+ copy->fpr = strdup(is->fpr);
+ }
+ copy->next = 0;
+ created.push_back(copy);
+ }
+ for (gpgme_invalid_key_t ik = r->invalid_signers ; ik ; ik = ik->next) {
+ gpgme_invalid_key_t copy = new _gpgme_invalid_key(*ik);
+ if (ik->fpr) {
+ copy->fpr = strdup(ik->fpr);
+ }
+ copy->next = 0;
+ invalid.push_back(copy);
+ }
+ }
+ ~Private()
+ {
+ for (std::vector<gpgme_new_signature_t>::iterator it = created.begin() ; it != created.end() ; ++it) {
+ std::free((*it)->fpr);
+ delete *it; *it = 0;
+ }
+ for (std::vector<gpgme_invalid_key_t>::iterator it = invalid.begin() ; it != invalid.end() ; ++it) {
+ std::free((*it)->fpr);
+ delete *it; *it = 0;
+ }
+ }
+
+ std::vector<gpgme_new_signature_t> created;
+ std::vector<gpgme_invalid_key_t> invalid;
+};
+
+GpgME::SigningResult::SigningResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::SigningResult::SigningResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::SigningResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_sign_result_t res = gpgme_op_sign_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(res));
+}
+
+make_standard_stuff(SigningResult)
+
+GpgME::CreatedSignature GpgME::SigningResult::createdSignature(unsigned int idx) const
+{
+ return CreatedSignature(d, idx);
+}
+
+std::vector<GpgME::CreatedSignature> GpgME::SigningResult::createdSignatures() const
+{
+ if (!d) {
+ return std::vector<CreatedSignature>();
+ }
+ std::vector<CreatedSignature> result;
+ result.reserve(d->created.size());
+ for (unsigned int i = 0 ; i < d->created.size() ; ++i) {
+ result.push_back(CreatedSignature(d, i));
+ }
+ return result;
+}
+
+GpgME::InvalidSigningKey GpgME::SigningResult::invalidSigningKey(unsigned int idx) const
+{
+ return InvalidSigningKey(d, idx);
+}
+
+std::vector<GpgME::InvalidSigningKey> GpgME::SigningResult::invalidSigningKeys() const
+{
+ if (!d) {
+ return std::vector<GpgME::InvalidSigningKey>();
+ }
+ std::vector<GpgME::InvalidSigningKey> result;
+ result.reserve(d->invalid.size());
+ for (unsigned int i = 0 ; i < d->invalid.size() ; ++i) {
+ result.push_back(InvalidSigningKey(d, i));
+ }
+ return result;
+}
+
+GpgME::InvalidSigningKey::InvalidSigningKey(const std::shared_ptr<SigningResult::Private> &parent, unsigned int i)
+ : d(parent), idx(i)
+{
+
+}
+
+GpgME::InvalidSigningKey::InvalidSigningKey() : d(), idx(0) {}
+
+bool GpgME::InvalidSigningKey::isNull() const
+{
+ return !d || idx >= d->invalid.size() ;
+}
+
+const char *GpgME::InvalidSigningKey::fingerprint() const
+{
+ return isNull() ? 0 : d->invalid[idx]->fpr ;
+}
+
+GpgME::Error GpgME::InvalidSigningKey::reason() const
+{
+ return Error(isNull() ? 0 : d->invalid[idx]->reason);
+}
+
+GpgME::CreatedSignature::CreatedSignature(const std::shared_ptr<SigningResult::Private> &parent, unsigned int i)
+ : d(parent), idx(i)
+{
+
+}
+
+GpgME::CreatedSignature::CreatedSignature() : d(), idx(0) {}
+
+bool GpgME::CreatedSignature::isNull() const
+{
+ return !d || idx >= d->created.size() ;
+}
+
+const char *GpgME::CreatedSignature::fingerprint() const
+{
+ return isNull() ? 0 : d->created[idx]->fpr ;
+}
+
+time_t GpgME::CreatedSignature::creationTime() const
+{
+ return static_cast<time_t>(isNull() ? 0 : d->created[idx]->timestamp);
+}
+
+GpgME::SignatureMode GpgME::CreatedSignature::mode() const
+{
+ if (isNull()) {
+ return NormalSignatureMode;
+ }
+ switch (d->created[idx]->type) {
+ default:
+ case GPGME_SIG_MODE_NORMAL: return NormalSignatureMode;
+ case GPGME_SIG_MODE_DETACH: return Detached;
+ case GPGME_SIG_MODE_CLEAR: return Clearsigned;
+ }
+}
+
+unsigned int GpgME::CreatedSignature::publicKeyAlgorithm() const
+{
+ return isNull() ? 0 : d->created[idx]->pubkey_algo ;
+}
+
+const char *GpgME::CreatedSignature::publicKeyAlgorithmAsString() const
+{
+ return gpgme_pubkey_algo_name(isNull() ? (gpgme_pubkey_algo_t)0 : d->created[idx]->pubkey_algo);
+}
+
+unsigned int GpgME::CreatedSignature::hashAlgorithm() const
+{
+ return isNull() ? 0 : d->created[idx]->hash_algo ;
+}
+
+const char *GpgME::CreatedSignature::hashAlgorithmAsString() const
+{
+ return gpgme_hash_algo_name(isNull() ? (gpgme_hash_algo_t)0 : d->created[idx]->hash_algo);
+}
+
+unsigned int GpgME::CreatedSignature::signatureClass() const
+{
+ return isNull() ? 0 : d->created[idx]->sig_class ;
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const SigningResult &result)
+{
+ os << "GpgME::SigningResult(";
+ if (!result.isNull()) {
+ os << "\n error: " << result.error()
+ << "\n createdSignatures:\n";
+ const std::vector<CreatedSignature> cs = result.createdSignatures();
+ std::copy(cs.begin(), cs.end(),
+ std::ostream_iterator<CreatedSignature>(os, "\n"));
+ os << " invalidSigningKeys:\n";
+ const std::vector<InvalidSigningKey> isk = result.invalidSigningKeys();
+ std::copy(isk.begin(), isk.end(),
+ std::ostream_iterator<InvalidSigningKey>(os, "\n"));
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const CreatedSignature &sig)
+{
+ os << "GpgME::CreatedSignature(";
+ if (!sig.isNull()) {
+ os << "\n fingerprint: " << protect(sig.fingerprint())
+ << "\n creationTime: " << sig.creationTime()
+ << "\n mode: " << sig.mode()
+ << "\n publicKeyAlgorithm: " << protect(sig.publicKeyAlgorithmAsString())
+ << "\n hashAlgorithm: " << protect(sig.hashAlgorithmAsString())
+ << "\n signatureClass: " << sig.signatureClass()
+ << '\n';
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const InvalidSigningKey &key)
+{
+ os << "GpgME::InvalidSigningKey(";
+ if (!key.isNull()) {
+ os << "\n fingerprint: " << protect(key.fingerprint())
+ << "\n reason: " << key.reason()
+ << '\n';
+ }
+ return os << ')';
+}
diff --git a/lang/cpp/src/signingresult.h b/lang/cpp/src/signingresult.h
new file mode 100644
index 0000000..2c27454
--- /dev/null
+++ b/lang/cpp/src/signingresult.h
@@ -0,0 +1,162 @@
+/*
+ signingresult.h - wraps a gpgme sign result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_SIGNINGRESULT_H__
+#define __GPGMEPP_SIGNINGRESULT_H__
+
+#include "global.h"
+#include "result.h"
+
+#include <time.h>
+
+#include <memory>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+class CreatedSignature;
+class InvalidSigningKey;
+
+class GPGMEPP_EXPORT SigningResult : public Result
+{
+public:
+ SigningResult();
+ SigningResult(gpgme_ctx_t ctx, int error);
+ SigningResult(gpgme_ctx_t ctx, const Error &error);
+ explicit SigningResult(const Error &err);
+
+ const SigningResult &operator=(SigningResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(SigningResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ CreatedSignature createdSignature(unsigned int index) const;
+ std::vector<CreatedSignature> createdSignatures() const;
+
+ InvalidSigningKey invalidSigningKey(unsigned int index) const;
+ std::vector<InvalidSigningKey> invalidSigningKeys() const;
+
+ class Private;
+private:
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const SigningResult &result);
+
+class GPGMEPP_EXPORT InvalidSigningKey
+{
+ friend class ::GpgME::SigningResult;
+ InvalidSigningKey(const std::shared_ptr<SigningResult::Private> &parent, unsigned int index);
+public:
+ InvalidSigningKey();
+
+ const InvalidSigningKey &operator=(InvalidSigningKey other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(InvalidSigningKey &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ swap(this->idx, other.idx);
+ }
+
+ bool isNull() const;
+
+ const char *fingerprint() const;
+ Error reason() const;
+
+private:
+ std::shared_ptr<SigningResult::Private> d;
+ unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const InvalidSigningKey &key);
+
+class GPGMEPP_EXPORT CreatedSignature
+{
+ friend class ::GpgME::SigningResult;
+ CreatedSignature(const std::shared_ptr<SigningResult::Private> &parent, unsigned int index);
+public:
+
+ CreatedSignature();
+
+ const CreatedSignature &operator=(CreatedSignature other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(CreatedSignature &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ swap(this->idx, other.idx);
+ }
+
+ bool isNull() const;
+
+ const char *fingerprint() const;
+
+ time_t creationTime() const;
+
+ SignatureMode mode() const;
+
+ unsigned int publicKeyAlgorithm() const;
+ const char *publicKeyAlgorithmAsString() const;
+
+ unsigned int hashAlgorithm() const;
+ const char *hashAlgorithmAsString() const;
+
+ unsigned int signatureClass() const;
+
+private:
+ std::shared_ptr<SigningResult::Private> d;
+ unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const CreatedSignature &sig);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(SigningResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(InvalidSigningKey)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(CreatedSignature)
+
+#endif // __GPGMEPP_SIGNINGRESULT_H__
diff --git a/lang/cpp/src/tofuinfo.cpp b/lang/cpp/src/tofuinfo.cpp
new file mode 100644
index 0000000..bb67fc8
--- /dev/null
+++ b/lang/cpp/src/tofuinfo.cpp
@@ -0,0 +1,167 @@
+/* tofuinfo.cpp - wraps gpgme tofu info
+ Copyright (C) 2016 Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "tofuinfo.h"
+
+#include <istream>
+#include "util.h"
+
+class GpgME::TofuInfo::Private
+{
+public:
+ Private() {}
+ Private(gpgme_tofu_info_t info)
+ : mInfo(info ? new _gpgme_tofu_info(*info) : nullptr)
+ {
+ if (mInfo && mInfo->description) {
+ mInfo->description = strdup(mInfo->description);
+ }
+ }
+
+ Private(const Private &other)
+ : mInfo(other.mInfo)
+ {
+ if (mInfo && mInfo->description) {
+ mInfo->description = strdup(mInfo->description);
+ }
+ }
+
+ ~Private()
+ {
+ if (mInfo) {
+ std::free(mInfo->description);
+ mInfo->description = nullptr;
+
+ delete mInfo;
+ }
+ }
+
+ gpgme_tofu_info_t mInfo;
+};
+
+GpgME::TofuInfo::TofuInfo(gpgme_tofu_info_t info)
+ : d(new Private(info))
+{
+}
+
+GpgME::TofuInfo::TofuInfo() : d()
+{
+}
+
+bool GpgME::TofuInfo::isNull() const
+{
+ return !d || !d->mInfo;
+}
+
+GpgME::TofuInfo::Validity GpgME::TofuInfo::validity() const
+{
+ if (isNull()) {
+ return ValidityUnknown;
+ }
+ switch (d->mInfo->validity) {
+ case 0:
+ return Conflict;
+ case 1:
+ return NoHistory;
+ case 2:
+ return LittleHistory;
+ case 3:
+ return BasicHistory;
+ case 4:
+ return LargeHistory;
+ default:
+ return ValidityUnknown;
+ }
+}
+
+GpgME::TofuInfo::Policy GpgME::TofuInfo::policy() const
+{
+ if (isNull()) {
+ return PolicyUnknown;
+ }
+ switch (d->mInfo->policy) {
+ case GPGME_TOFU_POLICY_NONE:
+ return PolicyNone;
+ case GPGME_TOFU_POLICY_AUTO:
+ return PolicyAuto;
+ case GPGME_TOFU_POLICY_GOOD:
+ return PolicyGood;
+ case GPGME_TOFU_POLICY_BAD:
+ return PolicyBad;
+ case GPGME_TOFU_POLICY_ASK:
+ return PolicyAsk;
+ case GPGME_TOFU_POLICY_UNKNOWN:
+ return PolicyUnknown;
+ }
+}
+
+const char *GpgME::TofuInfo::description() const
+{
+ return isNull() ? nullptr : d->mInfo->description;
+}
+
+unsigned short GpgME::TofuInfo::signCount() const
+{
+ return isNull() ? 0 : d->mInfo->signcount;
+}
+
+unsigned short GpgME::TofuInfo::encrCount() const
+{
+ return isNull() ? 0 : d->mInfo->encrcount;
+}
+
+unsigned long GpgME::TofuInfo::signFirst() const
+{
+ return isNull() ? 0 : d->mInfo->signfirst;
+}
+
+unsigned long GpgME::TofuInfo::signLast() const
+{
+ return isNull() ? 0 : d->mInfo->signlast;
+}
+
+unsigned long GpgME::TofuInfo::encrFirst() const
+{
+ return isNull() ? 0 : d->mInfo->encrfirst;
+}
+
+unsigned long GpgME::TofuInfo::encrLast() const
+{
+ return isNull() ? 0 : d->mInfo->encrlast;
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const GpgME::TofuInfo &info)
+{
+ os << "GpgME::Signature::TofuInfo(";
+ if (!info.isNull()) {
+ os << "\n desc: " << protect(info.description())
+ << "\n validity: " << info.validity()
+ << "\n policy: " << info.policy()
+ << "\n signcount: "<< info.signCount()
+ << "\n signfirst: "<< info.signFirst()
+ << "\n signlast: " << info.signLast()
+ << "\n encrcount: "<< info.encrCount()
+ << "\n encrfirst: "<< info.encrFirst()
+ << "\n encrlast: " << info.encrLast()
+ << '\n';
+ }
+ return os << ")";
+}
diff --git a/lang/cpp/src/tofuinfo.h b/lang/cpp/src/tofuinfo.h
new file mode 100644
index 0000000..c09c82a
--- /dev/null
+++ b/lang/cpp/src/tofuinfo.h
@@ -0,0 +1,124 @@
+/*
+ tofuinfo.h - wraps gpgme tofu info
+ Copyright (C) 2016 Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_TOFUINFO_H__
+#define __GPGMEPP_TOFUINFO_H__
+
+#include "gpgmepp_export.h"
+
+#include "gpgme.h"
+
+#include "global.h"
+
+#include <memory>
+
+namespace GpgME
+{
+
+class GPGMEPP_EXPORT TofuInfo
+{
+public:
+ TofuInfo();
+ explicit TofuInfo(gpgme_tofu_info_t info);
+
+ const TofuInfo &operator=(TofuInfo other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(TofuInfo &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ /* @enum Validity
+ * @brief The TOFU Validity. */
+ enum Validity : unsigned int {
+ /*! Unknown (uninitialized).*/
+ ValidityUnknown,
+ /*! TOFU Conflict.*/
+ Conflict,
+ /*! Key without history.*/
+ NoHistory,
+ /*! Key with too little history.*/
+ LittleHistory,
+ /*! Key with enough history for basic trust.*/
+ BasicHistory,
+ /*! Key with a lot of history.*/
+ LargeHistory,
+ };
+ Validity validity() const;
+
+ /* @enum Policy
+ * @brief The TOFU Validity. */
+ enum Policy : unsigned int {
+ /*! GPGME_TOFU_POLICY_NONE */
+ PolicyNone,
+ /*! GPGME_TOFU_POLICY_AUTO */
+ PolicyAuto,
+ /*! GPGME_TOFU_POLICY_GOOD */
+ PolicyGood,
+ /*! GPGME_TOFU_POLICY_UNKNOWN */
+ PolicyUnknown,
+ /*! GPGME_TOFU_POLICY_BAD */
+ PolicyBad,
+ /*! GPGME_TOFU_POLICY_ASK */
+ PolicyAsk,
+ };
+ Policy policy() const;
+
+ /* Number of signatures seen for this binding. Capped at USHRT_MAX. */
+ unsigned short signCount() const;
+
+ /* Number of encryption done to this binding. Capped at USHRT_MAX. */
+ unsigned short encrCount() const;
+
+ /** Number of seconds since epoch when the first message was verified */
+ unsigned long signFirst() const;
+
+ /** Number of seconds since epoch when the last message was verified */
+ unsigned long signLast() const;
+
+ /** Number of seconds since epoch when the first message was encrypted */
+ unsigned long encrFirst() const;
+
+ /** Number of seconds since epoch when the last message was encrypted */
+ unsigned long encrLast() const;
+
+ /* If non-NULL a human readable string summarizing the TOFU data. */
+ const char *description() const;
+
+private:
+ class Private;
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const TofuInfo &info);
+
+} // namespace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(TofuInfo)
+#endif // __GPGMEPP_TOFUINFO_H__
diff --git a/lang/cpp/src/trustitem.cpp b/lang/cpp/src/trustitem.cpp
new file mode 100644
index 0000000..fc7e4a6
--- /dev/null
+++ b/lang/cpp/src/trustitem.cpp
@@ -0,0 +1,114 @@
+/*
+ trustitem.cpp - wraps a gpgme trust item
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <trustitem.h>
+
+#include <gpgme.h>
+
+#include <cassert>
+
+namespace GpgME
+{
+
+class TrustItem::Private
+{
+public:
+ Private(gpgme_trust_item_t aItem)
+ : item(aItem)
+ {
+ }
+
+ gpgme_trust_item_t item;
+};
+
+TrustItem::TrustItem(gpgme_trust_item_t item)
+{
+ d = new Private(item);
+ if (d->item) {
+ gpgme_trust_item_ref(d->item);
+ }
+}
+
+TrustItem::TrustItem(const TrustItem &other)
+{
+ d = new Private(other.d->item);
+ if (d->item) {
+ gpgme_trust_item_ref(d->item);
+ }
+}
+
+TrustItem::~TrustItem()
+{
+ if (d->item) {
+ gpgme_trust_item_unref(d->item);
+ }
+ delete d; d = 0;
+}
+
+bool TrustItem::isNull() const
+{
+ return !d || !d->item;
+}
+
+gpgme_trust_item_t TrustItem::impl() const
+{
+ return d->item;
+}
+
+const char *TrustItem::keyID() const
+{
+ return d->item ? d->item->keyid : 0 ;
+}
+
+const char *TrustItem::userID() const
+{
+ return d->item ? d->item->name : 0 ;
+}
+
+const char *TrustItem::ownerTrustAsString() const
+{
+ return d->item ? d->item->owner_trust : 0 ;
+}
+
+const char *TrustItem::validityAsString() const
+{
+ return d->item ? d->item->validity : 0 ;
+}
+
+int TrustItem::trustLevel() const
+{
+ return d->item ? d->item->level : 0 ;
+}
+
+TrustItem::Type TrustItem::type() const
+{
+ if (!d->item) {
+ return Unknown;
+ } else {
+ return
+ d->item->type == 1 ? Key :
+ d->item->type == 2 ? UserID :
+ Unknown ;
+ }
+}
+
+} // namespace GpgME
diff --git a/lang/cpp/src/trustitem.h b/lang/cpp/src/trustitem.h
new file mode 100644
index 0000000..65f109c
--- /dev/null
+++ b/lang/cpp/src/trustitem.h
@@ -0,0 +1,81 @@
+/*
+ trustitem.h - wraps a gpgme trust item
+ Copyright (C) 2003 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_TRUSTITEM_H__
+#define __GPGMEPP_TRUSTITEM_H__
+
+#include "gpgmefw.h"
+#include <key.h>
+#include "gpgmepp_export.h"
+
+#include <algorithm>
+
+namespace GpgME
+{
+
+class Context;
+
+class GPGMEPP_EXPORT TrustItem
+{
+ friend class ::GpgME::Context;
+public:
+ explicit TrustItem(gpgme_trust_item_t item = 0);
+ TrustItem(const TrustItem &other);
+ virtual ~TrustItem();
+
+ const TrustItem &operator=(TrustItem other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(TrustItem &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ const char *keyID() const;
+ const char *userID() const;
+
+ const char *ownerTrustAsString() const;
+ const char *validityAsString() const;
+
+ int trustLevel() const;
+
+ enum Type { Unknown = 0, Key = 1, UserID = 2 };
+ Type type() const;
+
+private:
+ gpgme_trust_item_t impl() const;
+ class Private;
+ Private *d;
+};
+
+} // namepace GpgME
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(TrustItem)
+
+#endif // __GPGMEPP_TRUSTITEM_H__
diff --git a/lang/cpp/src/util.h b/lang/cpp/src/util.h
new file mode 100644
index 0000000..b0d47e3
--- /dev/null
+++ b/lang/cpp/src/util.h
@@ -0,0 +1,149 @@
+/*
+ util.h - some inline helper functions
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// -*- c++ -*-
+#ifndef __GPGMEPP_UTIL_H__
+#define __GPGMEPP_UTIL_H__
+
+#include "global.h"
+#include "notation.h"
+
+#include <gpgme.h>
+
+#ifndef NDEBUG
+#include <iostream>
+#endif
+#include <sstream>
+#include <string>
+
+static inline const char *protect(const char *s)
+{
+ return s ? s : "<null>" ;
+}
+
+static inline gpgme_error_t make_error(gpgme_err_code_t code)
+{
+ return gpgme_err_make((gpgme_err_source_t)22, code);
+}
+
+static inline unsigned long to_pid(const std::string &s)
+{
+ std::stringstream ss(s);
+ unsigned int result;
+ if (ss >> result) {
+ return result;
+ } else {
+ return 0U;
+ }
+}
+
+static inline gpgme_keylist_mode_t add_to_gpgme_keylist_mode_t(unsigned int oldmode, unsigned int newmodes)
+{
+ if (newmodes & GpgME::Local) {
+ oldmode |= GPGME_KEYLIST_MODE_LOCAL;
+ }
+ if (newmodes & GpgME::Extern) {
+ oldmode |= GPGME_KEYLIST_MODE_EXTERN;
+ }
+ if (newmodes & GpgME::Signatures) {
+ oldmode |= GPGME_KEYLIST_MODE_SIGS;
+ }
+ if (newmodes & GpgME::SignatureNotations) {
+ oldmode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
+ }
+ if (newmodes & GpgME::Ephemeral) {
+ oldmode |= GPGME_KEYLIST_MODE_EPHEMERAL;
+ }
+ if (newmodes & GpgME::Validate) {
+ oldmode |= GPGME_KEYLIST_MODE_VALIDATE;
+ }
+ if (newmodes & GpgME::WithTofu) {
+ oldmode |= GPGME_KEYLIST_MODE_WITH_TOFU;
+ }
+#ifndef NDEBUG
+ if (newmodes & ~(GpgME::Local | GpgME::Extern | GpgME::Signatures | GpgME::SignatureNotations | GpgME::Ephemeral | GpgME::Validate)) {
+ //std::cerr << "GpgME::Context: keylist mode must be one of Local, "
+ //"Extern, Signatures, SignatureNotations, or Validate, or a combination thereof!" << std::endl;
+ }
+#endif
+ return static_cast<gpgme_keylist_mode_t>(oldmode);
+}
+
+static inline unsigned int convert_from_gpgme_keylist_mode_t(unsigned int mode)
+{
+ unsigned int result = 0;
+ if (mode & GPGME_KEYLIST_MODE_LOCAL) {
+ result |= GpgME::Local;
+ }
+ if (mode & GPGME_KEYLIST_MODE_EXTERN) {
+ result |= GpgME::Extern;
+ }
+ if (mode & GPGME_KEYLIST_MODE_SIGS) {
+ result |= GpgME::Signatures;
+ }
+ if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) {
+ result |= GpgME::SignatureNotations;
+ }
+ if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) {
+ result |= GpgME::Ephemeral;
+ }
+ if (mode & GPGME_KEYLIST_MODE_VALIDATE) {
+ result |= GpgME::Validate;
+ }
+#ifndef NDEBUG
+ if (mode & ~(GPGME_KEYLIST_MODE_LOCAL |
+ GPGME_KEYLIST_MODE_EXTERN |
+ GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_EPHEMERAL |
+ GPGME_KEYLIST_MODE_VALIDATE |
+ GPGME_KEYLIST_MODE_SIGS)) {
+ //std::cerr << "GpgME: WARNING: gpgme_get_keylist_mode() returned an unknown flag!" << std::endl;
+ }
+#endif // NDEBUG
+ return result;
+}
+
+static inline GpgME::Notation::Flags convert_from_gpgme_sig_notation_flags_t(unsigned int flags)
+{
+ unsigned int result = 0;
+ if (flags & GPGME_SIG_NOTATION_HUMAN_READABLE) {
+ result |= GpgME::Notation::HumanReadable ;
+ }
+ if (flags & GPGME_SIG_NOTATION_CRITICAL) {
+ result |= GpgME::Notation::Critical ;
+ }
+ return static_cast<GpgME::Notation::Flags>(result);
+}
+
+static inline gpgme_sig_notation_flags_t add_to_gpgme_sig_notation_flags_t(unsigned int oldflags, unsigned int newflags)
+{
+ unsigned int result = oldflags;
+ if (newflags & GpgME::Notation::HumanReadable) {
+ result |= GPGME_SIG_NOTATION_HUMAN_READABLE;
+ }
+ if (newflags & GpgME::Notation::Critical) {
+ result |= GPGME_SIG_NOTATION_CRITICAL;
+ }
+ return static_cast<gpgme_sig_notation_flags_t>(result);
+}
+
+#endif // __GPGMEPP_UTIL_H__
diff --git a/lang/cpp/src/verificationresult.cpp b/lang/cpp/src/verificationresult.cpp
new file mode 100644
index 0000000..c62625d
--- /dev/null
+++ b/lang/cpp/src/verificationresult.cpp
@@ -0,0 +1,575 @@
+/*
+ verificationresult.cpp - wraps a gpgme verify result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <verificationresult.h>
+#include <notation.h>
+#include "result_p.h"
+#include "util.h"
+#include "key.h"
+
+#include <gpgme.h>
+
+#include <istream>
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+
+#include <string.h>
+
+class GpgME::VerificationResult::Private
+{
+public:
+ explicit Private(const gpgme_verify_result_t r)
+ {
+ if (!r) {
+ return;
+ }
+ if (r->file_name) {
+ file_name = r->file_name;
+ }
+ // copy recursively, using compiler-generated copy ctor.
+ // We just need to handle the pointers in the structs:
+ for (gpgme_signature_t is = r->signatures ; is ; is = is->next) {
+ gpgme_signature_t scopy = new _gpgme_signature(*is);
+ if (is->fpr) {
+ scopy->fpr = strdup(is->fpr);
+ }
+// PENDING(marc) why does this crash on Windows in strdup()?
+# ifndef _WIN32
+ if (is->pka_address) {
+ scopy->pka_address = strdup(is->pka_address);
+ }
+# else
+ scopy->pka_address = 0;
+# endif
+ scopy->next = 0;
+ sigs.push_back(scopy);
+ // copy keys
+ if (scopy->key) {
+ keys.push_back(Key(scopy->key, true));
+ }
+ // copy notations:
+ nota.push_back(std::vector<Nota>());
+ purls.push_back(0);
+ for (gpgme_sig_notation_t in = is->notations ; in ; in = in->next) {
+ if (!in->name) {
+ if (in->value) {
+ purls.back() = strdup(in->value); // policy url
+ }
+ continue;
+ }
+ Nota n = { 0, 0, in->flags };
+ n.name = strdup(in->name);
+ if (in->value) {
+ n.value = strdup(in->value);
+ }
+ nota.back().push_back(n);
+ }
+ }
+ }
+ ~Private()
+ {
+ for (std::vector<gpgme_signature_t>::iterator it = sigs.begin() ; it != sigs.end() ; ++it) {
+ std::free((*it)->fpr);
+ std::free((*it)->pka_address);
+ delete *it; *it = 0;
+ }
+ for (std::vector< std::vector<Nota> >::iterator it = nota.begin() ; it != nota.end() ; ++it) {
+ for (std::vector<Nota>::iterator jt = it->begin() ; jt != it->end() ; ++jt) {
+ std::free(jt->name); jt->name = 0;
+ std::free(jt->value); jt->value = 0;
+ }
+ }
+ std::for_each(purls.begin(), purls.end(), &std::free);
+ }
+
+ struct Nota {
+ char *name;
+ char *value;
+ gpgme_sig_notation_flags_t flags;
+ };
+
+ std::vector<gpgme_signature_t> sigs;
+ std::vector< std::vector<Nota> > nota;
+ std::vector<GpgME::Key> keys;
+ std::vector<char *> purls;
+ std::string file_name;
+};
+
+GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, int error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, const Error &error)
+ : GpgME::Result(error), d()
+{
+ init(ctx);
+}
+
+void GpgME::VerificationResult::init(gpgme_ctx_t ctx)
+{
+ if (!ctx) {
+ return;
+ }
+ gpgme_verify_result_t res = gpgme_op_verify_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(res));
+}
+
+make_standard_stuff(VerificationResult)
+
+const char *GpgME::VerificationResult::fileName() const
+{
+ return d ? d->file_name.c_str() : 0 ;
+}
+
+unsigned int GpgME::VerificationResult::numSignatures() const
+{
+ return d ? d->sigs.size() : 0 ;
+}
+
+GpgME::Signature GpgME::VerificationResult::signature(unsigned int idx) const
+{
+ return Signature(d, idx);
+}
+
+std::vector<GpgME::Signature> GpgME::VerificationResult::signatures() const
+{
+ if (!d) {
+ return std::vector<Signature>();
+ }
+ std::vector<Signature> result;
+ result.reserve(d->sigs.size());
+ for (unsigned int i = 0 ; i < d->sigs.size() ; ++i) {
+ result.push_back(Signature(d, i));
+ }
+ return result;
+}
+
+GpgME::Signature::Signature(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int i)
+ : d(parent), idx(i)
+{
+}
+
+GpgME::Signature::Signature() : d(), idx(0) {}
+
+bool GpgME::Signature::isNull() const
+{
+ return !d || idx >= d->sigs.size() ;
+}
+
+GpgME::Signature::Summary GpgME::Signature::summary() const
+{
+ if (isNull()) {
+ return None;
+ }
+ gpgme_sigsum_t sigsum = d->sigs[idx]->summary;
+ unsigned int result = 0;
+ if (sigsum & GPGME_SIGSUM_VALID) {
+ result |= Valid;
+ }
+ if (sigsum & GPGME_SIGSUM_GREEN) {
+ result |= Green;
+ }
+ if (sigsum & GPGME_SIGSUM_RED) {
+ result |= Red;
+ }
+ if (sigsum & GPGME_SIGSUM_KEY_REVOKED) {
+ result |= KeyRevoked;
+ }
+ if (sigsum & GPGME_SIGSUM_KEY_EXPIRED) {
+ result |= KeyExpired;
+ }
+ if (sigsum & GPGME_SIGSUM_SIG_EXPIRED) {
+ result |= SigExpired;
+ }
+ if (sigsum & GPGME_SIGSUM_KEY_MISSING) {
+ result |= KeyMissing;
+ }
+ if (sigsum & GPGME_SIGSUM_CRL_MISSING) {
+ result |= CrlMissing;
+ }
+ if (sigsum & GPGME_SIGSUM_CRL_TOO_OLD) {
+ result |= CrlTooOld;
+ }
+ if (sigsum & GPGME_SIGSUM_BAD_POLICY) {
+ result |= BadPolicy;
+ }
+ if (sigsum & GPGME_SIGSUM_SYS_ERROR) {
+ result |= SysError;
+ }
+ if (sigsum & GPGME_SIGSUM_TOFU_CONFLICT) {
+ result |= TofuConflict;
+ }
+ return static_cast<Summary>(result);
+}
+
+const char *GpgME::Signature::fingerprint() const
+{
+ return isNull() ? 0 : d->sigs[idx]->fpr ;
+}
+
+GpgME::Error GpgME::Signature::status() const
+{
+ return Error(isNull() ? 0 : d->sigs[idx]->status);
+}
+
+time_t GpgME::Signature::creationTime() const
+{
+ return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->timestamp);
+}
+
+time_t GpgME::Signature::expirationTime() const
+{
+ return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->exp_timestamp);
+}
+
+bool GpgME::Signature::neverExpires() const
+{
+ return expirationTime() == (time_t)0;
+}
+
+bool GpgME::Signature::isWrongKeyUsage() const
+{
+ return !isNull() && d->sigs[idx]->wrong_key_usage;
+}
+
+bool GpgME::Signature::isVerifiedUsingChainModel() const
+{
+ return !isNull() && d->sigs[idx]->chain_model;
+}
+
+GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const
+{
+ if (!isNull()) {
+ return static_cast<PKAStatus>(d->sigs[idx]->pka_trust);
+ }
+ return UnknownPKAStatus;
+}
+
+const char *GpgME::Signature::pkaAddress() const
+{
+ if (!isNull()) {
+ return d->sigs[idx]->pka_address;
+ }
+ return 0;
+}
+
+GpgME::Signature::Validity GpgME::Signature::validity() const
+{
+ if (isNull()) {
+ return Unknown;
+ }
+ switch (d->sigs[idx]->validity) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return Unknown;
+ case GPGME_VALIDITY_UNDEFINED: return Undefined;
+ case GPGME_VALIDITY_NEVER: return Never;
+ case GPGME_VALIDITY_MARGINAL: return Marginal;
+ case GPGME_VALIDITY_FULL: return Full;
+ case GPGME_VALIDITY_ULTIMATE: return Ultimate;
+ }
+}
+
+char GpgME::Signature::validityAsString() const
+{
+ if (isNull()) {
+ return '?';
+ }
+ switch (d->sigs[idx]->validity) {
+ default:
+ case GPGME_VALIDITY_UNKNOWN: return '?';
+ case GPGME_VALIDITY_UNDEFINED: return 'q';
+ case GPGME_VALIDITY_NEVER: return 'n';
+ case GPGME_VALIDITY_MARGINAL: return 'm';
+ case GPGME_VALIDITY_FULL: return 'f';
+ case GPGME_VALIDITY_ULTIMATE: return 'u';
+ }
+}
+
+GpgME::Error GpgME::Signature::nonValidityReason() const
+{
+ return Error(isNull() ? 0 : d->sigs[idx]->validity_reason);
+}
+
+unsigned int GpgME::Signature::publicKeyAlgorithm() const
+{
+ if (!isNull()) {
+ return d->sigs[idx]->pubkey_algo;
+ }
+ return 0;
+}
+
+const char *GpgME::Signature::publicKeyAlgorithmAsString() const
+{
+ if (!isNull()) {
+ return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo);
+ }
+ return 0;
+}
+
+unsigned int GpgME::Signature::hashAlgorithm() const
+{
+ if (!isNull()) {
+ return d->sigs[idx]->hash_algo;
+ }
+ return 0;
+}
+
+const char *GpgME::Signature::hashAlgorithmAsString() const
+{
+ if (!isNull()) {
+ return gpgme_hash_algo_name(d->sigs[idx]->hash_algo);
+ }
+ return 0;
+}
+
+const char *GpgME::Signature::policyURL() const
+{
+ return isNull() ? 0 : d->purls[idx] ;
+}
+
+GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const
+{
+ return GpgME::Notation(d, idx, nidx);
+}
+
+std::vector<GpgME::Notation> GpgME::Signature::notations() const
+{
+ if (isNull()) {
+ return std::vector<GpgME::Notation>();
+ }
+ std::vector<GpgME::Notation> result;
+ result.reserve(d->nota[idx].size());
+ for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) {
+ result.push_back(GpgME::Notation(d, idx, i));
+ }
+ return result;
+}
+
+GpgME::Key GpgME::Signature::key() const
+{
+ if (isNull()) {
+ return Key();
+ }
+ return d->keys[idx];
+}
+
+class GpgME::Notation::Private
+{
+public:
+ Private() : d(), sidx(0), nidx(0), nota(0) {}
+ Private(const std::shared_ptr<VerificationResult::Private> &priv, unsigned int sindex, unsigned int nindex)
+ : d(priv), sidx(sindex), nidx(nindex), nota(0)
+ {
+
+ }
+ Private(gpgme_sig_notation_t n)
+ : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0)
+ {
+ if (nota && nota->name) {
+ nota->name = strdup(nota->name);
+ }
+ if (nota && nota->value) {
+ nota->value = strdup(nota->value);
+ }
+ }
+ Private(const Private &other)
+ : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota)
+ {
+ if (nota) {
+ nota->name = strdup(nota->name);
+ nota->value = strdup(nota->value);
+ }
+ }
+ ~Private()
+ {
+ if (nota) {
+ std::free(nota->name); nota->name = 0;
+ std::free(nota->value); nota->value = 0;
+ delete nota;
+ }
+ }
+
+ std::shared_ptr<VerificationResult::Private> d;
+ unsigned int sidx, nidx;
+ gpgme_sig_notation_t nota;
+};
+
+GpgME::Notation::Notation(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex)
+ : d(new Private(parent, sindex, nindex))
+{
+
+}
+
+GpgME::Notation::Notation(gpgme_sig_notation_t nota)
+ : d(new Private(nota))
+{
+
+}
+
+GpgME::Notation::Notation() : d() {}
+
+bool GpgME::Notation::isNull() const
+{
+ if (!d) {
+ return true;
+ }
+ if (d->d) {
+ return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ;
+ }
+ return !d->nota;
+}
+
+const char *GpgME::Notation::name() const
+{
+ return
+ isNull() ? 0 :
+ d->d ? d->d->nota[d->sidx][d->nidx].name :
+ d->nota ? d->nota->name : 0 ;
+}
+
+const char *GpgME::Notation::value() const
+{
+ return
+ isNull() ? 0 :
+ d->d ? d->d->nota[d->sidx][d->nidx].value :
+ d->nota ? d->nota->value : 0 ;
+}
+
+GpgME::Notation::Flags GpgME::Notation::flags() const
+{
+ return
+ convert_from_gpgme_sig_notation_flags_t(
+ isNull() ? 0 :
+ d->d ? d->d->nota[d->sidx][d->nidx].flags :
+ d->nota ? d->nota->flags : 0);
+}
+
+bool GpgME::Notation::isHumanReadable() const
+{
+ return flags() & HumanReadable;
+}
+
+bool GpgME::Notation::isCritical() const
+{
+ return flags() & Critical;
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result)
+{
+ os << "GpgME::VerificationResult(";
+ if (!result.isNull()) {
+ os << "\n error: " << result.error()
+ << "\n fileName: " << protect(result.fileName())
+ << "\n signatures:\n";
+ const std::vector<Signature> sigs = result.signatures();
+ std::copy(sigs.begin(), sigs.end(),
+ std::ostream_iterator<Signature>(os, "\n"));
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus)
+{
+#define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
+ os << "GpgME::Signature::PKAStatus(";
+ OUTPUT(UnknownPKAStatus);
+ OUTPUT(PKAVerificationFailed);
+ OUTPUT(PKAVerificationSucceeded);
+#undef OUTPUT
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary)
+{
+#define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
+ os << "GpgME::Signature::Summary(";
+ OUTPUT(Valid);
+ OUTPUT(Green);
+ OUTPUT(Red);
+ OUTPUT(KeyRevoked);
+ OUTPUT(KeyExpired);
+ OUTPUT(SigExpired);
+ OUTPUT(KeyMissing);
+ OUTPUT(CrlMissing);
+ OUTPUT(CrlTooOld);
+ OUTPUT(BadPolicy);
+ OUTPUT(SysError);
+ OUTPUT(TofuConflict);
+#undef OUTPUT
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig)
+{
+ os << "GpgME::Signature(";
+ if (!sig.isNull()) {
+ os << "\n Summary: " << sig.summary()
+ << "\n Fingerprint: " << protect(sig.fingerprint())
+ << "\n Status: " << sig.status()
+ << "\n creationTime: " << sig.creationTime()
+ << "\n expirationTime: " << sig.expirationTime()
+ << "\n isWrongKeyUsage: " << sig.isWrongKeyUsage()
+ << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel()
+ << "\n pkaStatus: " << sig.pkaStatus()
+ << "\n pkaAddress: " << protect(sig.pkaAddress())
+ << "\n validity: " << sig.validityAsString()
+ << "\n nonValidityReason: " << sig.nonValidityReason()
+ << "\n publicKeyAlgorithm: " << protect(sig.publicKeyAlgorithmAsString())
+ << "\n hashAlgorithm: " << protect(sig.hashAlgorithmAsString())
+ << "\n policyURL: " << protect(sig.policyURL())
+ << "\n notations:\n";
+ const std::vector<Notation> nota = sig.notations();
+ std::copy(nota.begin(), nota.end(),
+ std::ostream_iterator<Notation>(os, "\n"));
+ }
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags)
+{
+ os << "GpgME::Notation::Flags(";
+#define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0)
+ OUTPUT(HumanReadable);
+ OUTPUT(Critical);
+#undef OUTPUT
+ return os << ')';
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const Notation &nota)
+{
+ os << "GpgME::Signature::Notation(";
+ if (!nota.isNull()) {
+ os << "\n name: " << protect(nota.name())
+ << "\n value: " << protect(nota.value())
+ << "\n flags: " << nota.flags()
+ << '\n';
+ }
+ return os << ")";
+}
diff --git a/lang/cpp/src/verificationresult.h b/lang/cpp/src/verificationresult.h
new file mode 100644
index 0000000..93288af
--- /dev/null
+++ b/lang/cpp/src/verificationresult.h
@@ -0,0 +1,180 @@
+/*
+ verificationresult.h - wraps a gpgme verify result
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_VERIFICATIONRESULT_H__
+#define __GPGMEPP_VERIFICATIONRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <time.h>
+
+#include <memory>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+class Signature;
+class Notation;
+class Key;
+
+class GPGMEPP_EXPORT VerificationResult : public Result
+{
+public:
+ VerificationResult();
+ VerificationResult(gpgme_ctx_t ctx, int error);
+ VerificationResult(gpgme_ctx_t ctx, const Error &error);
+ explicit VerificationResult(const Error &err);
+
+ const VerificationResult &operator=(VerificationResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(VerificationResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+
+ const char *fileName() const;
+
+ unsigned int numSignatures() const;
+ Signature signature(unsigned int index) const;
+ std::vector<Signature> signatures() const;
+
+ class Private;
+private:
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const VerificationResult &result);
+
+class GPGMEPP_EXPORT Signature
+{
+ friend class ::GpgME::VerificationResult;
+ Signature(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int index);
+public:
+ typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
+
+ Signature();
+
+ const Signature &operator=(Signature other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Signature &other)
+ {
+ using std::swap;
+ swap(this->d, other.d);
+ swap(this->idx, other.idx);
+ }
+
+ bool isNull() const;
+
+ enum Summary {
+ None = 0x000,
+ Valid = 0x001,
+ Green = 0x002,
+ Red = 0x004,
+ KeyRevoked = 0x008,
+ KeyExpired = 0x010,
+ SigExpired = 0x020,
+ KeyMissing = 0x040,
+ CrlMissing = 0x080,
+ CrlTooOld = 0x100,
+ BadPolicy = 0x200,
+ SysError = 0x400,
+ TofuConflict= 0x800
+ };
+ Summary summary() const;
+
+ const char *fingerprint() const;
+
+ Error status() const;
+
+ time_t creationTime() const;
+ time_t expirationTime() const;
+ bool neverExpires() const;
+
+ GPGMEPP_DEPRECATED bool wrongKeyUsage() const
+ {
+ return isWrongKeyUsage();
+ }
+ bool isWrongKeyUsage() const;
+ bool isVerifiedUsingChainModel() const;
+
+ enum PKAStatus {
+ UnknownPKAStatus, PKAVerificationFailed, PKAVerificationSucceeded
+ };
+ PKAStatus pkaStatus() const;
+ const char *pkaAddress() const;
+
+ enum Validity {
+ Unknown, Undefined, Never, Marginal, Full, Ultimate
+ };
+ Validity validity() const;
+ char validityAsString() const;
+ Error nonValidityReason() const;
+
+ unsigned int publicKeyAlgorithm() const;
+ const char *publicKeyAlgorithmAsString() const;
+
+ unsigned int hashAlgorithm() const;
+ const char *hashAlgorithmAsString() const;
+
+ const char *policyURL() const;
+ GpgME::Notation notation(unsigned int index) const;
+ std::vector<GpgME::Notation> notations() const;
+
+ /** Returns the key object associated with this signature.
+ * May be incomplete but will have at least the fingerprint
+ * set or the associated TOFU Information if applicable. */
+ GpgME::Key key() const;
+
+private:
+ std::shared_ptr<VerificationResult::Private> d;
+ unsigned int idx;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Signature &sig);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Signature::PKAStatus pkaStatus);
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, Signature::Summary summary);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(VerificationResult)
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Signature)
+
+#endif // __GPGMEPP_VERIFICATIONRESULT_H__
diff --git a/lang/cpp/src/vfsmountresult.cpp b/lang/cpp/src/vfsmountresult.cpp
new file mode 100644
index 0000000..c9fdd5e
--- /dev/null
+++ b/lang/cpp/src/vfsmountresult.cpp
@@ -0,0 +1,90 @@
+/*
+ vfsmountresult.cpp - wraps a gpgme vfs mount result
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB <info@kdab.com>
+ Author: Marc Mutz <marc@kdab.com>, Volker Krause <volker@kdab.com>
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <vfsmountresult.h>
+#include "result_p.h"
+
+#include <gpgme.h>
+
+#include <istream>
+#include <string.h>
+
+using namespace GpgME;
+
+class VfsMountResult::Private
+{
+public:
+ explicit Private(const gpgme_vfs_mount_result_t r) : mountDir(0)
+ {
+ if (r && r->mount_dir) {
+ mountDir = strdup(r->mount_dir);
+ }
+ }
+
+ ~Private()
+ {
+ std::free(mountDir);
+ }
+
+ char *mountDir;
+};
+
+VfsMountResult::VfsMountResult(gpgme_ctx_t ctx, const Error &error, const Error &opError)
+ : Result(error ? error : opError), d()
+{
+ init(ctx);
+}
+
+void VfsMountResult::init(gpgme_ctx_t ctx)
+{
+ (void)ctx;
+ if (!ctx) {
+ return;
+ }
+ gpgme_vfs_mount_result_t res = gpgme_op_vfs_mount_result(ctx);
+ if (!res) {
+ return;
+ }
+ d.reset(new Private(res));
+}
+
+make_standard_stuff(VfsMountResult)
+
+const char *VfsMountResult::mountDir() const
+{
+ if (d) {
+ return d->mountDir;
+ }
+ return 0;
+}
+
+std::ostream &GpgME::operator<<(std::ostream &os, const VfsMountResult &result)
+{
+ os << "GpgME::VfsMountResult(";
+ if (!result.isNull()) {
+ os << "\n error: " << result.error()
+ << "\n mount dir: " << result.mountDir()
+ << "\n";
+ }
+ return os << ')';
+}
diff --git a/lang/cpp/src/vfsmountresult.h b/lang/cpp/src/vfsmountresult.h
new file mode 100644
index 0000000..b46eeb1
--- /dev/null
+++ b/lang/cpp/src/vfsmountresult.h
@@ -0,0 +1,76 @@
+/*
+ vfsmountresult.h - wraps a gpgme vfs mount result
+ Copyright (C) 2009 Klarälvdalens Datakonsult AB <info@kdab.com>
+ Author: Marc Mutz <marc@kdab.com>, Volker Krause <volker@kdab.com>
+
+ This file is part of GPGME++.
+
+ GPGME++ is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __GPGMEPP_VFSMOUNTRESULT_H__
+#define __GPGMEPP_VFSMOUNTRESULT_H__
+
+#include "gpgmefw.h"
+#include "result.h"
+#include "gpgmepp_export.h"
+
+#include <memory>
+
+#include <vector>
+#include <iosfwd>
+
+namespace GpgME
+{
+
+class Error;
+
+class GPGMEPP_EXPORT VfsMountResult : public Result
+{
+public:
+ VfsMountResult();
+ VfsMountResult(gpgme_ctx_t ctx, const Error &error, const Error &opError);
+ explicit VfsMountResult(const Error &err);
+
+ const VfsMountResult &operator=(VfsMountResult other)
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(VfsMountResult &other)
+ {
+ Result::swap(other);
+ using std::swap;
+ swap(this->d, other.d);
+ }
+
+ bool isNull() const;
+ const char *mountDir() const;
+
+ class Private;
+private:
+ void init(gpgme_ctx_t ctx);
+ std::shared_ptr<Private> d;
+};
+
+GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const VfsMountResult &result);
+
+}
+
+GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(VfsMountResult)
+
+#endif // __GPGMEPP_VFSMOUNTRESULT_H__
diff --git a/lang/python/MANIFEST.in b/lang/python/MANIFEST.in
new file mode 100644
index 0000000..eefdb83
--- /dev/null
+++ b/lang/python/MANIFEST.in
@@ -0,0 +1,4 @@
+recursive-include examples *.py
+include gpgme-h-clean.py gpgme.i
+include helpers.c helpers.h private.h
+recursive-include pyme *.py
diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
new file mode 100644
index 0000000..2271ce0
--- /dev/null
+++ b/lang/python/Makefile.am
@@ -0,0 +1,106 @@
+# Makefile.am for the Python bindings.
+# 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/>.
+
+EXTRA_DIST = \
+ README \
+ MANIFEST.in \
+ gpgme.i \
+ helpers.c helpers.h private.h \
+ gpgme-h-clean.py \
+ examples \
+ pyme
+
+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_PYME = \
+ $(srcdir)/pyme/callbacks.py \
+ $(srcdir)/pyme/constants \
+ $(srcdir)/pyme/core.py \
+ $(srcdir)/pyme/errors.py \
+ $(srcdir)/pyme/__init__.py \
+ $(srcdir)/pyme/results.py \
+ $(srcdir)/pyme/util.py
+
+# For VPATH builds we need to copy some files because Python's
+# distutils are not VPATH-aware.
+copystamp: $(COPY_FILES) $(COPY_FILES_PYME)
+ if test "$(srcdir)" != "$(builddir)" ; then \
+ cp -R $(COPY_FILES) . ; \
+ cp -R $(COPY_FILES_PYME) pyme ; \
+ fi
+ touch $@
+
+all-local: copystamp
+ for PYTHON in $(PYTHONS); do \
+ CFLAGS="$(CFLAGS) -I$(top_srcdir)" \
+ $$PYTHON setup.py build --verbose ; \
+ done
+
+dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc: copystamp
+ CFLAGS="$(CFLAGS) -I$(top_srcdir)" \
+ $(PYTHON) setup.py sdist --verbose
+ gpg2 --detach-sign --armor dist/pyme3-$(VERSION).tar.gz
+
+.PHONY: sdist
+sdist: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc
+
+.PHONY: upload
+upload: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc
+ twine upload $^
+
+CLEANFILES = gpgme.h errors.i gpgme_wrap.c pyme/gpgme.py \
+ copystamp
+
+# Remove the rest.
+#
+# 'make distclean' clears the write bit, breaking rm -rf. Fix the
+# permissions.
+clean-local:
+ rm -rf -- build
+ if test "$(srcdir)" != "$(builddir)" ; then \
+ find . -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+ for F in $(COPY_FILES); do rm -rf -- `basename $$F` ; done ; \
+ for F in $(COPY_FILES_PYME); do \
+ rm -rf -- pyme/`basename $$F` ; \
+ done ; \
+ fi
+
+install-exec-local:
+ rm -f install_files.txt
+ for PYTHON in $(PYTHONS); do \
+ $$PYTHON setup.py install \
+ --prefix $(DESTDIR)$(prefix) \
+ --record files.txt \
+ --verbose ; \
+ cat files.txt >> install_files.txt ; \
+ rm files.txt ; \
+ done
+ $(MKDIR_P) $(DESTDIR)$(pythondir)/pyme
+ mv install_files.txt $(DESTDIR)$(pythondir)/pyme
+
+uninstall-local:
+ xargs <$(DESTDIR)$(pythondir)/pyme/install_files.txt -- rm -rf --
+ rm -rf -- $(DESTDIR)$(pythondir)/pyme
diff --git a/lang/python/Makefile.in b/lang/python/Makefile.in
new file mode 100644
index 0000000..6e6cfe6
--- /dev/null
+++ b/lang/python/Makefile.in
@@ -0,0 +1,798 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for the Python bindings.
+# 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/>.
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/python
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs $(srcdir)/setup.py.in \
+ README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = setup.py
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+ README \
+ MANIFEST.in \
+ gpgme.i \
+ helpers.c helpers.h private.h \
+ gpgme-h-clean.py \
+ examples \
+ pyme
+
+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_PYME = \
+ $(srcdir)/pyme/callbacks.py \
+ $(srcdir)/pyme/constants \
+ $(srcdir)/pyme/core.py \
+ $(srcdir)/pyme/errors.py \
+ $(srcdir)/pyme/__init__.py \
+ $(srcdir)/pyme/results.py \
+ $(srcdir)/pyme/util.py
+
+CLEANFILES = gpgme.h errors.i gpgme_wrap.c pyme/gpgme.py \
+ copystamp
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/python/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/python/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+setup.py: $(top_builddir)/config.status $(srcdir)/setup.py.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile all-local
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-exec-local
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-local
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \
+ check check-am clean clean-generic clean-libtool clean-local \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-exec-local install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am uninstall-local
+
+
+# For VPATH builds we need to copy some files because Python's
+# distutils are not VPATH-aware.
+copystamp: $(COPY_FILES) $(COPY_FILES_PYME)
+ if test "$(srcdir)" != "$(builddir)" ; then \
+ cp -R $(COPY_FILES) . ; \
+ cp -R $(COPY_FILES_PYME) pyme ; \
+ fi
+ touch $@
+
+all-local: copystamp
+ for PYTHON in $(PYTHONS); do \
+ CFLAGS="$(CFLAGS) -I$(top_srcdir)" \
+ $$PYTHON setup.py build --verbose ; \
+ done
+
+dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc: copystamp
+ CFLAGS="$(CFLAGS) -I$(top_srcdir)" \
+ $(PYTHON) setup.py sdist --verbose
+ gpg2 --detach-sign --armor dist/pyme3-$(VERSION).tar.gz
+
+.PHONY: sdist
+sdist: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc
+
+.PHONY: upload
+upload: dist/pyme3-$(VERSION).tar.gz dist/pyme3-$(VERSION).tar.gz.asc
+ twine upload $^
+
+# Remove the rest.
+#
+# 'make distclean' clears the write bit, breaking rm -rf. Fix the
+# permissions.
+clean-local:
+ rm -rf -- build
+ if test "$(srcdir)" != "$(builddir)" ; then \
+ find . -type d ! -perm -200 -exec chmod u+w {} ';' ; \
+ for F in $(COPY_FILES); do rm -rf -- `basename $$F` ; done ; \
+ for F in $(COPY_FILES_PYME); do \
+ rm -rf -- pyme/`basename $$F` ; \
+ done ; \
+ fi
+
+install-exec-local:
+ rm -f install_files.txt
+ for PYTHON in $(PYTHONS); do \
+ $$PYTHON setup.py install \
+ --prefix $(DESTDIR)$(prefix) \
+ --record files.txt \
+ --verbose ; \
+ cat files.txt >> install_files.txt ; \
+ rm files.txt ; \
+ done
+ $(MKDIR_P) $(DESTDIR)$(pythondir)/pyme
+ mv install_files.txt $(DESTDIR)$(pythondir)/pyme
+
+uninstall-local:
+ xargs <$(DESTDIR)$(pythondir)/pyme/install_files.txt -- rm -rf --
+ rm -rf -- $(DESTDIR)$(pythondir)/pyme
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/python/README b/lang/python/README
new file mode 100644
index 0000000..98c007e
--- /dev/null
+++ b/lang/python/README
@@ -0,0 +1,59 @@
+PyME - GPGME for Python -*- org -*-
+=======================
+
+PyME is a python interface to the GPGME library:
+https://www.gnupg.org/related_software/gpgme/
+
+PyME offers two interfaces, one is a high-level, curated, and
+idiomatic interface that is implemented as a shim on top of the
+low-level interface automatically created using SWIG.
+
+This way we make simple things easy, while still providing the entire
+functionality of the underlying library.
+
+* Mailing List
+
+For general discussion and help see the gnupg-users mailing list:
+https://lists.gnupg.org/mailman/listinfo/gnupg-users
+
+For development see the gnupg-devel mailing list:
+https://lists.gnupg.org/mailman/listinfo/gnupg-devel
+
+* Bugs
+
+Please report bugs using our bug tracker using the category 'gpgme',
+and topic 'python':
+https://bugs.gnupg.org/gnupg/
+
+* Authors
+
+PyME has been created by John Goerzen, and maintained, developed, and
+cherished by Igor Belyi, Martin Albrecht, Ben McGinnes, and everyone
+who contributed to it in any way.
+
+In 2016 we merged a port of PyME to into the GPGME repository, and
+development will continue there. Please see the VCS history for the
+list of contributors, and if you do find bugs, or want to contribute,
+please get in touch and help maintain PyME.
+
+Please see the section 'History' further down this document for
+references to previous versions.
+
+* History
+
+ - The bindings have been merged into the GPGME repository in 2016.
+
+ - The latest version of PyME for Python 3.2 and above (as of
+ May, 2015) is v0.9.1.
+ https://git.gnupg.org/gpgme.git/lang/py3-pyme
+
+ - The latest version of PyME for Python 2.6 and 2.7 (as of this
+ writing) is v0.9.0. https://bitbucket.org/malb/pyme
+
+ - A previous version of PyME v0.8.0 can be found on sourceforge:
+ http://pyme.sourceforge.net/
+
+ - A previous version of PyME v0.5.1 which works with GPGME v0.3.15
+ can be found on John Goerzen's PyME page:
+ http://quux.org/devel/pyme/
+ http://www.complete.org/JohnGoerzen
diff --git a/lang/python/examples/assuan.py b/lang/python/examples/assuan.py
new file mode 100644
index 0000000..22960d3
--- /dev/null
+++ b/lang/python/examples/assuan.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Demonstrate the use of the Assuan protocol engine"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import pyme
+
+with pyme.Context(protocol=pyme.constants.PROTOCOL_ASSUAN) as c:
+ # Invoke the pinentry to get a confirmation.
+ err = c.assuan_transact(['GET_CONFIRMATION', 'Hello there'])
+ print("You chose {}.".format("cancel" if err else "ok"))
diff --git a/lang/python/examples/decryption-filter.py b/lang/python/examples/decryption-filter.py
new file mode 100644
index 0000000..3007c2b
--- /dev/null
+++ b/lang/python/examples/decryption-filter.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""A decryption filter
+
+This demonstrates decryption using pyme3 in three lines of code. To
+be used like this:
+
+./decryption-filter.py <message.gpg >message.plain
+
+"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+pyme.Context().decrypt(sys.stdin, sink=sys.stdout)
diff --git a/lang/python/examples/delkey.py b/lang/python/examples/delkey.py
new file mode 100755
index 0000000..a02f412
--- /dev/null
+++ b/lang/python/examples/delkey.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Sample of key deletion
+# It deletes keys for joe@example.org generated by genkey.py script
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import pyme
+
+with pyme.Context() as c:
+ # Note: We must not modify the key store during iteration,
+ # therefore, we explicitly make a list.
+ keys = list(c.keylist("joe+pyme@example.org"))
+
+ for k in keys:
+ c.op_delete(k, True)
diff --git a/lang/python/examples/encrypt-to-all.py b/lang/python/examples/encrypt-to-all.py
new file mode 100755
index 0000000..35873bd
--- /dev/null
+++ b/lang/python/examples/encrypt-to-all.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2008 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""
+This program will try to encrypt a simple message to each key on your
+keyring. If your keyring has any invalid keys on it, those keys will
+be skipped and it will re-try the encryption."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+
+with pyme.Context(armor=True) as c:
+ recipients = list()
+ for key in c.keylist():
+ valid = 0
+ if any(sk.can_encrypt for sk in key.subkeys):
+ recipients.append(key)
+ print("Adding recipient {0}.".format(key.uids[0].uid))
+
+ ciphertext = None
+ while not ciphertext:
+ print("Encrypting to %d recipients" % len(recipients))
+ try:
+ ciphertext, _, _ = c.encrypt(b'This is my message.',
+ recipients=recipients)
+ except pyme.errors.InvalidRecipients as e:
+ print("Encryption failed for these keys:\n{0!s}".format(e))
+
+ # filter out the bad keys
+ bad_keys = {bad.fpr for bad in e.recipients}
+ recipients = [r for r in recipients
+ if not r.subkeys[0].fpr in bad_keys]
+
+ sys.stdout.buffer.write(ciphertext)
diff --git a/lang/python/examples/exportimport.py b/lang/python/examples/exportimport.py
new file mode 100755
index 0000000..bc946bc
--- /dev/null
+++ b/lang/python/examples/exportimport.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Sample of export and import of keys
+# It uses keys for joe+pyme@example.org generated by genkey.py script
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import os
+import pyme
+
+user = "joe+pyme@example.org"
+
+with pyme.Context(armor=True) as c, pyme.Data() as expkey:
+ print(" - Export %s's public keys - " % user)
+ c.op_export(user, 0, expkey)
+
+ # print out exported data to see how it looks in armor.
+ expkey.seek(0, os.SEEK_SET)
+ expstring = expkey.read()
+ if expstring:
+ sys.stdout.buffer.write(expstring)
+ else:
+ sys.exit("No %s's keys to export!" % user)
+
+# delete keys to ensure that they came from our imported data. Note
+# that if joe's key has private part as well we can only delete both
+# of them.
+with pyme.Context() as c:
+ # Note: We must not modify the key store during iteration,
+ # therfore, we explicitly make a list.
+ keys = list(c.keylist(user))
+
+ for k in keys:
+ c.op_delete(k, True)
+
+with pyme.Context() as c:
+ print(" - Import exported keys - ")
+ c.op_import(expstring)
+ result = c.op_import_result()
+ if result:
+ print(result)
+ else:
+ sys.exit(" - No import result - ")
diff --git a/lang/python/examples/genkey.py b/lang/python/examples/genkey.py
new file mode 100755
index 0000000..ee70303
--- /dev/null
+++ b/lang/python/examples/genkey.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import pyme
+
+# This is the example from the GPGME manual.
+
+parms = """<GnupgKeyParms format="internal">
+Key-Type: RSA
+Key-Length: 2048
+Subkey-Type: RSA
+Subkey-Length: 2048
+Name-Real: Joe Tester
+Name-Comment: with stupid passphrase
+Name-Email: joe+pyme@example.org
+Passphrase: Crypt0R0cks
+Expire-Date: 2020-12-31
+</GnupgKeyParms>
+"""
+
+with pyme.Context() as c:
+ c.set_progress_cb(pyme.callbacks.progress_stdout)
+ c.op_genkey(parms, None, None)
+ print("Generated key with fingerprint {0}.".format(
+ c.op_genkey_result().fpr))
diff --git a/lang/python/examples/inter-edit.py b/lang/python/examples/inter-edit.py
new file mode 100644
index 0000000..39d6f17
--- /dev/null
+++ b/lang/python/examples/inter-edit.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2005 Igor Belyi <belyi@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""Simple interactive editor to test editor scripts"""
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+
+if len(sys.argv) != 2:
+ sys.exit("Usage: %s <Gpg key pattern>\n" % sys.argv[0])
+
+name = sys.argv[1]
+
+with pyme.Context() as c:
+ keys = list(c.keylist(name))
+ if len(keys) == 0:
+ sys.exit("No key matching {}.".format(name))
+ if len(keys) > 1:
+ sys.exit("More than one key matching {}.".format(name))
+
+ key = keys[0]
+ print("Editing key {} ({}):".format(key.uids[0].uid, key.subkeys[0].fpr))
+
+ def edit_fnc(keyword, args):
+ print("Status: {} ({}), args: {} > ".format(
+ keyword, status, args), end='', flush=True)
+
+ if not 'GET' in keyword:
+ # no prompt
+ print()
+ return None
+
+ try:
+ return input()
+ except EOFError:
+ return "quit"
+
+ c.interact(key, edit_fnc, sink=sys.stdout)
diff --git a/lang/python/examples/sign.py b/lang/python/examples/sign.py
new file mode 100755
index 0000000..2f235ba
--- /dev/null
+++ b/lang/python/examples/sign.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+from pyme.constants.sig import mode
+
+with pyme.Context() as c:
+ signed, _ = c.sign(b"Test message", mode=mode.CLEAR)
+ sys.stdout.buffer.write(signed)
diff --git a/lang/python/examples/signverify.py b/lang/python/examples/signverify.py
new file mode 100755
index 0000000..03bc0a6
--- /dev/null
+++ b/lang/python/examples/signverify.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Sample of unattended signing/verifying of a message.
+# It uses keys for joe+pyme@example.org generated by genkey.py script
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+from pyme.constants.sig import mode
+
+user = "joe+pyme"
+
+with pyme.Context(pinentry_mode=pyme.constants.PINENTRY_MODE_LOOPBACK) as c:
+ keys = list(c.keylist(user))
+ if len(keys) == 0:
+ sys.exit("No key matching {}.".format(user))
+
+ c.signers = keys[:1]
+ c.set_passphrase_cb(lambda *args: "Crypt0R0cks")
+ signed_data, _ = c.sign(b"Test message", mode=mode.CLEAR)
+
+ data, result = c.verify(signed_data, verify=keys[:1])
+ print("Data: {!r}\nSignature: {!s}".format(data, result.signatures[0]))
diff --git a/lang/python/examples/simple.py b/lang/python/examples/simple.py
new file mode 100755
index 0000000..5598487
--- /dev/null
+++ b/lang/python/examples/simple.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2005 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+
+with pyme.Context(armor=True) as c:
+ recipients = []
+ print("Enter name of your recipient(s), end with a blank line.")
+ while True:
+ line = input()
+ if not line:
+ break
+ new = list(c.keylist(line))
+ if not new:
+ print("Matched no known keys.")
+ else:
+ print("Adding {}.".format(", ".join(k.uids[0].name for k in new)))
+ recipients.extend(new)
+
+ if not recipients:
+ sys.exit("No recipients.")
+
+ print("Encrypting for {}.".format(", ".join(k.uids[0].name
+ for k in recipients)))
+
+ ciphertext, _, _ = c.encrypt(b"This is my message,", recipients)
+ sys.stdout.buffer.write(ciphertext)
diff --git a/lang/python/examples/testCMSgetkey.py b/lang/python/examples/testCMSgetkey.py
new file mode 100644
index 0000000..4467b6c
--- /dev/null
+++ b/lang/python/examples/testCMSgetkey.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2008 Bernhard Reiter <bernhard@intevation.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+"""A test applicaton for the CMS protocol."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+import pyme
+
+if len(sys.argv) != 2:
+ sys.exit("fingerprint or unique key ID for gpgme_get_key()")
+
+with pyme.Context(protocol=pyme.constants.PROTOCOL_CMS) as c:
+ key = c.get_key(sys.argv[1], False)
+
+ print("got key: ", key.subkeys[0].fpr)
+ for uid in key.uids:
+ print(uid.uid)
diff --git a/lang/python/examples/verifydetails.py b/lang/python/examples/verifydetails.py
new file mode 100755
index 0000000..fa34926
--- /dev/null
+++ b/lang/python/examples/verifydetails.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (c) 2008 Bernhard Reiter <bernhard@intevation.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+import sys
+from pyme import core
+from pyme.constants import protocol
+
+def print_engine_infos():
+ print("gpgme version:", core.check_version(None))
+ print("engines:")
+
+ for engine in core.get_engine_info():
+ print(engine.file_name, engine.version)
+
+ for proto in [protocol.OpenPGP, protocol.CMS]:
+ print("Have {}? {}".format(core.get_protocol_name(proto),
+ core.engine_check_version(proto)))
+
+
+def verifyprintdetails(filename, detached_sig_filename=None):
+ """Verify a signature, print a lot of details."""
+ with core.Context() as c:
+
+ # Verify.
+ data, result = c.verify(open(filename),
+ open(detached_sig_filename)
+ if detached_sig_filename else None)
+
+ # List results for all signatures. Status equal 0 means "Ok".
+ for index, sign in enumerate(result.signatures):
+ print("signature", index, ":")
+ print(" summary: %#0x" % (sign.summary))
+ print(" status: %#0x" % (sign.status))
+ print(" timestamp: ", sign.timestamp)
+ print(" fingerprint:", sign.fpr)
+ print(" uid: ", c.get_key(sign.fpr, 0).uids[0].uid)
+
+ # Print "unsigned" text if inline signature
+ if data:
+ sys.stdout.buffer.write(data)
+
+def main():
+ print_engine_infos()
+ print()
+
+ argc = len(sys.argv)
+ if argc < 2 or argc > 3:
+ sys.exit(
+ "Usage: {} <filename>[ <detached_signature_filename>]".format(
+ sys.argv[0]))
+
+ if argc == 2:
+ print("trying to verify file {}.".format(sys.argv[1]))
+ verifyprintdetails(sys.argv[1])
+ if argc == 3:
+ print("trying to verify signature {1} for file {0}.".format(*sys.argv))
+ verifyprintdetails(sys.argv[1], sys.argv[2])
+
+if __name__ == "__main__":
+ main()
diff --git a/lang/python/gpgme-h-clean.py b/lang/python/gpgme-h-clean.py
new file mode 100755
index 0000000..52f8676
--- /dev/null
+++ b/lang/python/gpgme-h-clean.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@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/gpgme.i b/lang/python/gpgme.i
new file mode 100644
index 0000000..84addae
--- /dev/null
+++ b/lang/python/gpgme.i
@@ -0,0 +1,625 @@
+/*
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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
+*/
+%module gpgme
+%include "cpointer.i"
+%include "cstring.i"
+
+/* Generate doc strings for all methods.
+
+ This will generate docstrings of the form
+
+ gpgme_op_encrypt(ctx, recp, flags, plain, cipher) -> gpgme_error_t
+
+ which we transform into
+
+ ctx.op_encrypt(recp, flags, plain, cipher) -> gpgme_error_t
+
+ for automagically wrapped functions. */
+%feature("autodoc", "0");
+
+
+/* Allow use of Unicode objects, bytes, and None for strings. */
+%typemap(in) const char *(PyObject *encodedInput = NULL) {
+ if ($input == Py_None)
+ $1 = NULL;
+ else if (PyUnicode_Check($input))
+ {
+ encodedInput = PyUnicode_AsUTF8String($input);
+ if (encodedInput == NULL)
+ return NULL;
+ $1 = PyBytes_AsString(encodedInput);
+ }
+ else if (PyBytes_Check($input))
+ $1 = PyBytes_AsString($input);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: expected str, bytes, or None, got %s",
+ $argnum, $input->ob_type->tp_name);
+ return NULL;
+ }
+}
+%typemap(freearg) const char * {
+ Py_XDECREF(encodedInput$argnum);
+}
+
+/* Likewise for a list of strings. */
+%typemap(in) const char *[] (void *vector = NULL,
+ size_t size,
+ PyObject **pyVector = NULL) {
+ /* Check if is a list */
+ if (PyList_Check($input)) {
+ size_t i, j;
+ size = PyList_Size($input);
+ $1 = (char **) (vector = malloc((size+1) * sizeof(char *)));
+ pyVector = calloc(sizeof *pyVector, size);
+
+ for (i = 0; i < size; i++) {
+ PyObject *o = PyList_GetItem($input,i);
+ if (PyUnicode_Check(o))
+ {
+ pyVector[i] = PyUnicode_AsUTF8String(o);
+ if (pyVector[i] == NULL)
+ {
+ free(vector);
+ for (j = 0; j < i; j++)
+ Py_XDECREF(pyVector[j]);
+ return NULL;
+ }
+ $1[i] = PyBytes_AsString(pyVector[i]);
+ }
+ else if (PyString_Check(o))
+ $1[i] = PyString_AsString(o);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: list must contain only str or bytes, got %s "
+ "at position %d",
+ $argnum, o->ob_type->tp_name, i);
+ free($1);
+ return NULL;
+ }
+ }
+ $1[i] = NULL;
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: expected a list of str or bytes, got %s",
+ $argnum, $input->ob_type->tp_name);
+ return NULL;
+ }
+}
+%typemap(freearg) const char *[] {
+ size_t i;
+ free(vector$argnum);
+ for (i = 0; i < size$argnum; i++)
+ Py_XDECREF(pyVector$argnum[i]);
+}
+
+// Release returned buffers as necessary.
+%typemap(newfree) char * "free($1);";
+%newobject gpgme_data_release_and_get_mem;
+
+%typemap(arginit) gpgme_key_t [] {
+ $1 = NULL;
+}
+
+%typemap(in) gpgme_key_t [] {
+ int i, numb = 0;
+ if (!PySequence_Check($input)) {
+ PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t",
+ $argnum);
+ return NULL;
+ }
+ if((numb = PySequence_Length($input)) != 0) {
+ $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t));
+ for(i=0; i<numb; i++) {
+ PyObject *pypointer = PySequence_GetItem($input, i);
+
+ /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
+ /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */
+
+ // Following code is from swig's python.swg
+ if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) {
+ Py_DECREF(pypointer);
+ return NULL;
+ }
+ Py_DECREF(pypointer);
+ }
+ $1[numb] = NULL;
+ }
+}
+%typemap(freearg) gpgme_key_t [] {
+ if ($1) free($1);
+}
+
+// Special handling for references to our objects.
+%typemap(in) gpgme_data_t DATAIN (gpgme_data_t wrapper = NULL,
+ PyObject *bytesio = NULL,
+ Py_buffer view, int have_view = 0) {
+ /* If we create a temporary wrapper object, we will store it in
+ wrapperN, where N is $argnum. Here in this fragment, SWIG will
+ automatically append $argnum. */
+ memset(&view, 0, sizeof view);
+ if ($input == Py_None)
+ $1 = NULL;
+ else {
+ PyObject *pypointer;
+ pypointer = _pyme_obj2gpgme_data_t($input, $argnum, &wrapper,
+ &bytesio, &view);
+ if (pypointer == NULL)
+ return NULL;
+ have_view = !! view.obj;
+
+ /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
+
+ // Following code is from swig's python.swg
+
+ if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor,
+ SWIG_POINTER_EXCEPTION | $disown )) == -1) {
+ Py_DECREF(pypointer);
+ return NULL;
+ }
+ Py_DECREF(pypointer);
+ }
+}
+
+#if HAVE_DATA_H
+/* If we are doing an in-tree build, we can use the internal
+ representation of struct gpgme_data for an very efficient check if
+ the buffer has been modified. */
+%{
+#include "src/data.h" /* For struct gpgme_data. */
+%}
+#endif
+
+%typemap(freearg) gpgme_data_t DATAIN {
+ /* See whether we need to update the Python buffer. */
+ if (resultobj && wrapper$argnum && view$argnum.buf)
+ {
+ int dirty;
+ char *new_data = NULL;
+ size_t new_size;
+
+#if HAVE_DATA_H
+ new_data = wrapper$argnum->data.mem.buffer;
+ new_size = wrapper$argnum->data.mem.length;
+ dirty = new_data != NULL;
+#else
+ new_data = gpgme_data_release_and_get_mem (wrapper$argnum, &new_size);
+ wrapper$argnum = NULL;
+ dirty = new_size != view$argnum.len
+ || memcmp (new_data, view$argnum.buf, view$argnum.len);
+#endif
+
+ if (dirty)
+ {
+ /* The buffer is dirty. */
+ if (view$argnum.readonly)
+ {
+ Py_XDECREF(resultobj);
+ resultobj = NULL;
+ PyErr_SetString(PyExc_ValueError,
+ "cannot update read-only buffer");
+ }
+
+ /* See if we need to truncate the buffer. */
+ if (resultobj && view$argnum.len != new_size)
+ {
+ if (bytesio$argnum == NULL)
+ {
+ Py_XDECREF(resultobj);
+ resultobj = NULL;
+ PyErr_SetString(PyExc_ValueError, "cannot resize buffer");
+ }
+ else
+ {
+ PyObject *retval;
+ PyBuffer_Release(&view$argnum);
+ assert(view$argnum.obj == NULL);
+ retval = PyObject_CallMethod(bytesio$argnum, "truncate",
+ "l", (long) new_size);
+ if (retval == NULL)
+ {
+ Py_XDECREF(resultobj);
+ resultobj = NULL;
+ }
+ else
+ {
+ Py_DECREF(retval);
+
+ retval = PyObject_CallMethod(bytesio$argnum,
+ "getbuffer", NULL);
+ if (retval == NULL
+ || PyObject_GetBuffer(retval, &view$argnum,
+ PyBUF_SIMPLE|PyBUF_WRITABLE) < 0)
+ {
+ Py_XDECREF(resultobj);
+ resultobj = NULL;
+ }
+
+ Py_XDECREF(retval);
+
+ if (resultobj && view$argnum.len
+ != new_size)
+ {
+ Py_XDECREF(resultobj);
+ resultobj = NULL;
+ PyErr_Format(PyExc_ValueError,
+ "Expected buffer of length %zu, got %zi",
+ new_size,
+ view$argnum.len);
+ }
+ }
+ }
+ }
+ if (resultobj)
+ memcpy(view$argnum.buf, new_data, new_size);
+ }
+#if ! HAVE_DATA_H
+ free (new_data);
+#endif
+ }
+
+ /* Free the temporary wrapper, if any. */
+ if (wrapper$argnum)
+ gpgme_data_release(wrapper$argnum);
+ Py_XDECREF (bytesio$argnum);
+ if (have_view$argnum && view$argnum.buf)
+ PyBuffer_Release(&view$argnum);
+}
+
+%apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,
+ gpgme_data_t sig, gpgme_data_t signed_text,
+ gpgme_data_t plaintext, gpgme_data_t keydata,
+ gpgme_data_t pubkey, gpgme_data_t seckey,
+ gpgme_data_t out};
+
+/* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in
+ gpgme.h. */
+/* XXX: This is wrong at least for off_t if compiled with LFS. */
+%typemap(out) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
+ $result = PyLong_FromLong($1);
+}
+/* XXX: This is wrong at least for off_t if compiled with LFS. */
+%typemap(in) ssize_t, off_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
+ $1 = PyLong_AsLong($input);
+}
+
+// Those are for gpgme_data_read() and gpgme_strerror_r()
+%typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
+ $2 = PyLong_AsLong($input);
+ if ($2 < 0) {
+ PyErr_SetString(PyExc_ValueError, "Positive integer expected");
+ return NULL;
+ }
+ $1 = ($1_ltype) malloc($2+1);
+}
+%typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) {
+ Py_XDECREF($result); /* Blow away any previous result */
+ if (result < 0) { /* Check for I/O error */
+ free($1);
+ return PyErr_SetFromErrno(PyExc_RuntimeError);
+ }
+ $result = PyBytes_FromStringAndSize($1,result);
+ free($1);
+}
+
+/* For gpgme_data_write, but should be universal. */
+%typemap(in) (const void *buffer, size_t size)(PyObject *encodedInput = NULL) {
+ Py_ssize_t ssize;
+
+ if ($input == Py_None)
+ $1 = NULL, $2 = 0;
+ else if (PyUnicode_Check($input))
+ {
+ encodedInput = PyUnicode_AsUTF8String($input);
+ if (encodedInput == NULL)
+ return NULL;
+ if (PyBytes_AsStringAndSize(encodedInput, (char **) &$1, &ssize) == -1)
+ {
+ Py_DECREF(encodedInput);
+ return NULL;
+ }
+ }
+ else if (PyBytes_Check($input))
+ PyBytes_AsStringAndSize($input, (char **) &$1, &ssize);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: expected str, bytes, or None, got %s",
+ $argnum, $input->ob_type->tp_name);
+ return NULL;
+ }
+
+ if (! $1)
+ $2 = 0;
+ else
+ {
+ assert (ssize >= 0);
+ $2 = (size_t) ssize;
+ }
+}
+%typemap(freearg) (const void *buffer, size_t size) {
+ Py_XDECREF(encodedInput$argnum);
+}
+
+// Make types containing 'next' field to be lists
+%ignore next;
+%typemap(out) gpgme_sig_notation_t, gpgme_subkey_t,
+ gpgme_key_sig_t, gpgme_user_id_t, gpgme_invalid_key_t,
+ gpgme_recipient_t, gpgme_new_signature_t, gpgme_signature_t,
+ gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t,
+ gpgme_conf_comp_t, gpgme_tofu_info_t {
+ int i;
+ int size = 0;
+ $1_ltype curr;
+ for (curr = $1; curr != NULL; curr = curr->next) {
+ size++;
+ }
+ $result = PyList_New(size);
+ for (i=0,curr=$1; i<size; i++,curr=curr->next) {
+ PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags);
+ PyList_SetItem($result, i, o);
+ }
+}
+
+
+
+/* Wrap the fragile result objects into robust Python ones. */
+%typemap(out) gpgme_encrypt_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "EncryptResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_decrypt_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "DecryptResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_sign_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "SignResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_verify_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "VerifyResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_import_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "ImportResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_genkey_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "GenkeyResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_keylist_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "KeylistResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_vfs_mount_result_t {
+ PyObject *fragile;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
+ %newpointer_flags);
+ $result = _pyme_wrap_result(fragile, "VFSMountResult");
+ Py_DECREF(fragile);
+}
+
+%typemap(out) gpgme_engine_info_t {
+ int i;
+ int size = 0;
+ $1_ltype curr;
+ for (curr = $1; curr != NULL; curr = curr->next) {
+ size++;
+ }
+ $result = PyList_New(size);
+ if ($result == NULL)
+ return NULL; /* raise */
+ for (i=0,curr=$1; i<size; i++,curr=curr->next) {
+ PyObject *fragile, *o;
+ fragile = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor,
+ %newpointer_flags);
+ if (fragile == NULL)
+ {
+ Py_DECREF($result);
+ return NULL; /* raise */
+ }
+ o = _pyme_wrap_result(fragile, "EngineInfo");
+ Py_DECREF(fragile);
+ if (o == NULL)
+ {
+ Py_DECREF($result);
+ return NULL; /* raise */
+ }
+ PyList_SetItem($result, i, o);
+ }
+}
+
+
+
+/* Include mapper for interact callbacks. */
+%typemap(in) (gpgme_interact_cb_t fnc, void *fnc_value) {
+ if (! PyTuple_Check($input))
+ return PyErr_Format(PyExc_TypeError, "interact callback must be a tuple");
+ if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3)
+ return PyErr_Format(PyExc_TypeError,
+ "interact callback must be a tuple of size 2 or 3");
+
+ $1 = (gpgme_interact_cb_t) _pyme_interact_cb;
+ $2 = $input;
+}
+
+
+
+/* The assuan protocol callbacks. */
+%typemap(in) (gpgme_assuan_data_cb_t data_cb, void *data_cb_value) {
+ if ($input == Py_None)
+ $1 = $2 = NULL;
+ else
+ {
+ if (! PyTuple_Check($input))
+ return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
+ if (PyTuple_Size($input) != 2)
+ return PyErr_Format(PyExc_TypeError,
+ "callback must be a tuple of size 2");
+ if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
+ return PyErr_Format(PyExc_TypeError, "second item must be callable");
+ $1 = _pyme_assuan_data_cb;
+ $2 = $input;
+ }
+}
+
+%typemap(in) (gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value) {
+ if ($input == Py_None)
+ $1 = $2 = NULL;
+ else
+ {
+ if (! PyTuple_Check($input))
+ return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
+ if (PyTuple_Size($input) != 2)
+ return PyErr_Format(PyExc_TypeError,
+ "callback must be a tuple of size 2");
+ if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
+ return PyErr_Format(PyExc_TypeError, "second item must be callable");
+ $1 = _pyme_assuan_inquire_cb;
+ $2 = $input;
+ }
+}
+
+%typemap(in) (gpgme_assuan_status_cb_t stat_cb, void *stat_cb_value) {
+ if ($input == Py_None)
+ $1 = $2 = NULL;
+ else
+ {
+ if (! PyTuple_Check($input))
+ return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
+ if (PyTuple_Size($input) != 2)
+ return PyErr_Format(PyExc_TypeError,
+ "callback must be a tuple of size 2");
+ if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
+ return PyErr_Format(PyExc_TypeError, "second item must be callable");
+ $1 = _pyme_assuan_status_cb;
+ $2 = $input;
+ }
+}
+
+/* Include the unmodified <gpgme.h> for cc, and the cleaned-up local
+ version for SWIG. We do, however, want to hide certain fields on
+ some structs, which we provide prior to including the version for
+ SWIG. */
+%{
+#include <gpgme.h>
+%}
+
+/* This is for notations, where we want to hide the length fields, and
+ the unused bit field block. */
+struct _gpgme_sig_notation
+{
+ struct _gpgme_sig_notation *next;
+
+ /* If NAME is a null pointer, then VALUE contains a policy URL
+ rather than a notation. */
+ char *name;
+
+ /* The value of the notation data. */
+ char *value;
+
+ /* The accumulated flags. */
+ gpgme_sig_notation_flags_t flags;
+
+ /* Notation data is human-readable. */
+ unsigned int human_readable : 1;
+
+ /* Notation data is critical. */
+ unsigned int critical : 1;
+};
+
+/* Now include our local modified version. Any structs defined above
+ are ignored. */
+%include "gpgme.h"
+
+%include "errors.i"
+
+// Generating and handling pointers-to-pointers.
+
+%pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p);
+%pointer_functions(gpgme_data_t, gpgme_data_t_p);
+%pointer_functions(gpgme_key_t, gpgme_key_t_p);
+%pointer_functions(gpgme_error_t, gpgme_error_t_p);
+%pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p);
+%pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p);
+
+// Helper functions.
+
+%{
+#include <stdio.h>
+%}
+FILE *fdopen(int fildes, const char *mode);
+
+/* We include both headers in the generated c code... */
+%{
+#include "helpers.h"
+#include "private.h"
+
+/* SWIG runtime support for helpers.c */
+PyObject *
+_pyme_wrap_gpgme_data_t(gpgme_data_t data)
+{
+ return SWIG_Python_NewPointerObj(NULL, data, SWIGTYPE_p_gpgme_data, 0);
+}
+
+gpgme_ctx_t
+_pyme_unwrap_gpgme_ctx_t(PyObject *wrapped)
+{
+ gpgme_ctx_t result;
+ if (SWIG_ConvertPtr(wrapped,
+ (void **) &result,
+ SWIGTYPE_p_gpgme_context,
+ SWIG_POINTER_EXCEPTION) == -1)
+ return NULL;
+ return result;
+}
+%}
+
+/* ... but only the public definitions here. They will be exposed to
+ the Python world, so let's be careful. */
+%include "helpers.h"
diff --git a/lang/python/helpers.c b/lang/python/helpers.c
new file mode 100644
index 0000000..f9aec91
--- /dev/null
+++ b/lang/python/helpers.c
@@ -0,0 +1,1169 @@
+/*
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <gpgme.h>
+#include <stdlib.h>
+#include <string.h>
+#include "Python.h"
+
+#include "helpers.h"
+#include "private.h"
+
+/* Flag specifying whether this is an in-tree build. */
+int pyme_in_tree_build =
+#if IN_TREE_BUILD
+ 1
+#else
+ 0
+#endif
+ ;
+
+static PyObject *GPGMEError = NULL;
+
+void _pyme_exception_init(void) {
+ if (GPGMEError == NULL) {
+ PyObject *errors;
+ PyObject *from_list = PyList_New(0);
+ errors = PyImport_ImportModuleLevel("errors", PyEval_GetGlobals(),
+ PyEval_GetLocals(), from_list, 1);
+ Py_XDECREF(from_list);
+ if (errors) {
+ GPGMEError=PyDict_GetItemString(PyModule_GetDict(errors), "GPGMEError");
+ Py_XINCREF(GPGMEError);
+ }
+ }
+}
+
+static PyObject *
+_pyme_raise_exception(gpgme_error_t err)
+{
+ PyObject *e;
+
+ _pyme_exception_init();
+ if (GPGMEError == NULL)
+ return PyErr_Format(PyExc_RuntimeError, "Got gpgme_error_t %d", err);
+
+ e = PyObject_CallFunction(GPGMEError, "l", (long) err);
+ if (e == NULL)
+ return NULL;
+
+ PyErr_SetObject(GPGMEError, e);
+ Py_DECREF(e);
+
+ return NULL; /* raise */
+}
+
+gpgme_error_t _pyme_exception2code(void) {
+ gpgme_error_t err_status = gpg_error(GPG_ERR_GENERAL);
+ if (GPGMEError && PyErr_ExceptionMatches(GPGMEError)) {
+ PyObject *type = 0, *value = 0, *traceback = 0;
+ PyObject *error = 0;
+ PyErr_Fetch(&type, &value, &traceback);
+ PyErr_NormalizeException(&type, &value, &traceback);
+ error = PyObject_GetAttrString(value, "error");
+ err_status = PyLong_AsLong(error);
+ Py_DECREF(error);
+ PyErr_Restore(type, value, traceback);
+ }
+ return err_status;
+}
+
+/* Exception support for callbacks. */
+#define EXCINFO "_callback_excinfo"
+
+static void _pyme_stash_callback_exception(PyObject *weak_self)
+{
+ PyObject *self, *ptype, *pvalue, *ptraceback, *excinfo;
+
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+ excinfo = PyTuple_New(3);
+ PyTuple_SetItem(excinfo, 0, ptype);
+
+ if (pvalue)
+ PyTuple_SetItem(excinfo, 1, pvalue);
+ else {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(excinfo, 1, Py_None);
+ }
+
+ if (ptraceback)
+ PyTuple_SetItem(excinfo, 2, ptraceback);
+ else {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(excinfo, 2, Py_None);
+ }
+
+ self = PyWeakref_GetObject(weak_self);
+ /* self only has a borrowed reference. */
+ if (self == Py_None) {
+ /* This should not happen, as even if we're called from the data
+ release callback triggered from the wrappers destructor, the
+ object is still alive and hence the weak reference still refers
+ to the object. However, in case this ever changes, not seeing
+ any exceptions is worse than having a little extra code, so
+ here we go. */
+ fprintf(stderr,
+ "Error occurred in callback, but the wrapper object "
+ "has been deallocated.\n");
+ PyErr_Restore(ptype, pvalue, ptraceback);
+ PyErr_Print();
+ }
+ else
+ PyObject_SetAttrString(self, EXCINFO, excinfo);
+ Py_DECREF(excinfo);
+}
+
+PyObject *pyme_raise_callback_exception(PyObject *self)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *ptype, *pvalue, *ptraceback, *excinfo;
+
+ if (! PyObject_HasAttrString(self, EXCINFO))
+ goto leave;
+
+ excinfo = PyObject_GetAttrString(self, EXCINFO);
+ if (! PyTuple_Check(excinfo))
+ {
+ Py_DECREF(excinfo);
+ goto leave;
+ }
+
+ ptype = PyTuple_GetItem(excinfo, 0);
+ Py_INCREF(excinfo);
+
+ pvalue = PyTuple_GetItem(excinfo, 1);
+ if (pvalue == Py_None)
+ pvalue = NULL;
+ else
+ Py_INCREF(pvalue);
+
+ ptraceback = PyTuple_GetItem(excinfo, 2);
+ if (ptraceback == Py_None)
+ ptraceback = NULL;
+ else
+ Py_INCREF(ptraceback);
+
+ /* We now have references for the extracted items. */
+ Py_DECREF(excinfo);
+
+ /* Clear the exception information. It is important to do this
+ before setting the error, because setting the attribute may
+ execute python code, and the runtime system raises a SystemError
+ if an exception is set but values are returned. */
+ Py_INCREF(Py_None);
+ PyObject_SetAttrString(self, EXCINFO, Py_None);
+
+ /* Restore exception. */
+ PyErr_Restore(ptype, pvalue, ptraceback);
+ PyGILState_Release(state);
+ return NULL; /* Raise exception. */
+
+ leave:
+ Py_INCREF(Py_None);
+ PyGILState_Release(state);
+ return Py_None;
+}
+#undef EXCINFO
+
+/* Argument conversion. */
+
+/* Convert object to a pointer to gpgme type, generic version. */
+PyObject *
+_pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum)
+{
+ PyObject *pyname = NULL, *pypointer = NULL;
+ pyname = PyObject_GetAttrString(input, "_ctype");
+ if (pyname && PyUnicode_Check(pyname))
+ {
+ PyObject *encoded = PyUnicode_AsUTF8String(pyname);
+ if (strcmp(PyBytes_AsString(encoded), objtype) != 0)
+ {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: Expected value of type %s, but got %s",
+ argnum, objtype, PyBytes_AsString(encoded));
+ Py_DECREF(encoded);
+ Py_DECREF(pyname);
+ return NULL;
+ }
+ Py_DECREF(encoded);
+ }
+ else
+ return NULL;
+
+ Py_DECREF(pyname);
+ pypointer = PyObject_GetAttrString(input, "wrapped");
+ if (pypointer == NULL) {
+ PyErr_Format(PyExc_TypeError,
+ "arg %d: Use of uninitialized Python object %s",
+ argnum, objtype);
+ return NULL;
+ }
+ return pypointer;
+}
+
+/* Convert object to a pointer to gpgme type, version for data
+ objects. Constructs a wrapper Python on the fly e.g. for file-like
+ objects with a fileno method, returning it in WRAPPER. This object
+ must be de-referenced when no longer needed. */
+PyObject *
+_pyme_obj2gpgme_data_t(PyObject *input, int argnum, gpgme_data_t *wrapper,
+ PyObject **bytesio, Py_buffer *view)
+{
+ gpgme_error_t err;
+ PyObject *data;
+ PyObject *fd;
+
+ /* See if it is a file-like object with file number. */
+ fd = PyObject_CallMethod(input, "fileno", NULL);
+ if (fd) {
+ err = gpgme_data_new_from_fd(wrapper, (int) PyLong_AsLong(fd));
+ Py_DECREF(fd);
+ if (err)
+ return _pyme_raise_exception (err);
+
+ return _pyme_wrap_gpgme_data_t(*wrapper);
+ }
+ else
+ PyErr_Clear();
+
+ /* No? Maybe it implements the buffer protocol. */
+ data = PyObject_CallMethod(input, "getbuffer", NULL);
+ if (data)
+ {
+ /* Save a reference to input, which seems to be a BytesIO
+ object. */
+ Py_INCREF(input);
+ *bytesio = input;
+ }
+ else
+ {
+ PyErr_Clear();
+
+ /* No, but maybe the user supplied a buffer object? */
+ data = input;
+ }
+
+ /* Do we have a buffer object? */
+ if (PyObject_CheckBuffer(data))
+ {
+ if (PyObject_GetBuffer(data, view, PyBUF_SIMPLE) < 0)
+ return NULL;
+
+ if (data != input)
+ Py_DECREF(data);
+
+ assert (view->obj);
+ assert (view->ndim == 1);
+ assert (view->shape == NULL);
+ assert (view->strides == NULL);
+ assert (view->suboffsets == NULL);
+
+ err = gpgme_data_new_from_mem(wrapper, view->buf, (size_t) view->len, 0);
+ if (err)
+ return _pyme_raise_exception (err);
+
+ return _pyme_wrap_gpgme_data_t(*wrapper);
+ }
+
+ /* As last resort we assume it is a wrapped data object. */
+ if (PyObject_HasAttrString(data, "_ctype"))
+ return _pyme_obj2gpgme_t(data, "gpgme_data_t", argnum);
+
+ return PyErr_Format(PyExc_TypeError,
+ "arg %d: expected pyme.Data, file, or an object "
+ "implementing the buffer protocol, got %s",
+ argnum, data->ob_type->tp_name);
+}
+
+
+
+PyObject *
+_pyme_wrap_result(PyObject *fragile, const char *classname)
+{
+ static PyObject *results;
+ PyObject *class;
+ PyObject *replacement;
+
+ if (results == NULL)
+ {
+ PyObject *from_list = PyList_New(0);
+ if (from_list == NULL)
+ return NULL;
+
+ results = PyImport_ImportModuleLevel("results", PyEval_GetGlobals(),
+ PyEval_GetLocals(), from_list, 1);
+ Py_DECREF(from_list);
+
+ if (results == NULL)
+ return NULL;
+ }
+
+ class = PyMapping_GetItemString(PyModule_GetDict(results), classname);
+ if (class == NULL)
+ return NULL;
+
+ replacement = PyObject_CallFunctionObjArgs(class, fragile, NULL);
+ Py_DECREF(class);
+ return replacement;
+}
+
+
+
+/* Callback support. */
+static gpgme_error_t pyPassphraseCb(void *hook,
+ const char *uid_hint,
+ const char *passphrase_info,
+ int prev_was_bad,
+ int fd) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *args = NULL;
+ PyObject *retval = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *encoded = NULL;
+ gpgme_error_t err_status = 0;
+
+ _pyme_exception_init();
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ if (PyTuple_Size(pyhook) == 3) {
+ dataarg = PyTuple_GetItem(pyhook, 2);
+ args = PyTuple_New(4);
+ } else {
+ args = PyTuple_New(3);
+ }
+
+ if (uid_hint == NULL)
+ {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(args, 0, Py_None);
+ }
+ else
+ PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(uid_hint, strlen (uid_hint),
+ "strict"));
+ if (PyErr_Occurred()) {
+ Py_DECREF(args);
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+
+ PyTuple_SetItem(args, 1, PyBytes_FromString(passphrase_info));
+ PyTuple_SetItem(args, 2, PyBool_FromLong((long)prev_was_bad));
+ if (dataarg) {
+ Py_INCREF(dataarg); /* Because GetItem doesn't give a ref but SetItem taketh away */
+ PyTuple_SetItem(args, 3, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, args);
+ Py_DECREF(args);
+ if (PyErr_Occurred()) {
+ err_status = _pyme_exception2code();
+ } else {
+ if (!retval) {
+ if (write(fd, "\n", 1) < 0) {
+ err_status = gpgme_error_from_syserror ();
+ _pyme_raise_exception (err_status);
+ }
+ } else {
+ char *buf;
+ size_t len;
+ if (PyBytes_Check(retval))
+ buf = PyBytes_AsString(retval), len = PyBytes_Size(retval);
+ else if (PyUnicode_Check(retval))
+ {
+ Py_ssize_t ssize;
+ encoded = PyUnicode_AsUTF8String(retval);
+ if (encoded == NULL)
+ {
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+ if (PyBytes_AsStringAndSize(encoded, &buf, &ssize) == -1)
+ {
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+ assert (! buf || ssize >= 0);
+ len = (size_t) ssize;
+ }
+ else
+ {
+ PyErr_Format(PyExc_TypeError,
+ "expected str or bytes from passphrase callback, got %s",
+ retval->ob_type->tp_name);
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+
+ if (write(fd, buf, len) < 0) {
+ err_status = gpgme_error_from_syserror ();
+ _pyme_raise_exception (err_status);
+ }
+ if (! err_status && write(fd, "\n", 1) < 0) {
+ err_status = gpgme_error_from_syserror ();
+ _pyme_raise_exception (err_status);
+ }
+
+ Py_DECREF(retval);
+ }
+ }
+
+ leave:
+ if (err_status)
+ _pyme_stash_callback_exception(self);
+
+ Py_XDECREF(encoded);
+ PyGILState_Release(state);
+ return err_status;
+}
+
+PyObject *
+pyme_set_passphrase_cb(PyObject *self, PyObject *cb) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *wrapped;
+ gpgme_ctx_t ctx;
+
+ wrapped = PyObject_GetAttrString(self, "wrapped");
+ if (wrapped == NULL)
+ {
+ assert (PyErr_Occurred ());
+ PyGILState_Release(state);
+ return NULL;
+ }
+
+ ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
+ Py_DECREF(wrapped);
+ if (ctx == NULL)
+ {
+ if (cb == Py_None)
+ goto out;
+ else
+ return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
+ }
+
+ if (cb == Py_None) {
+ gpgme_set_passphrase_cb(ctx, NULL, NULL);
+ PyObject_SetAttrString(self, "_passphrase_cb", Py_None);
+ goto out;
+ }
+
+ if (! PyTuple_Check(cb))
+ return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
+ if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
+ return PyErr_Format(PyExc_TypeError,
+ "cb must be a tuple of size 2 or 3");
+
+ gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t) pyPassphraseCb,
+ (void *) cb);
+ PyObject_SetAttrString(self, "_passphrase_cb", cb);
+
+ out:
+ Py_INCREF(Py_None);
+ PyGILState_Release(state);
+ return Py_None;
+}
+
+static void pyProgressCb(void *hook, const char *what, int type, int current,
+ int total) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *func = NULL, *dataarg = NULL, *args = NULL, *retval = NULL;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ if (PyTuple_Size(pyhook) == 3) {
+ dataarg = PyTuple_GetItem(pyhook, 2);
+ args = PyTuple_New(5);
+ } else {
+ args = PyTuple_New(4);
+ }
+
+ PyTuple_SetItem(args, 0, PyUnicode_DecodeUTF8(what, strlen (what),
+ "strict"));
+ if (PyErr_Occurred()) {
+ _pyme_stash_callback_exception(self);
+ Py_DECREF(args);
+ PyGILState_Release(state);
+ return;
+ }
+ PyTuple_SetItem(args, 1, PyLong_FromLong((long) type));
+ PyTuple_SetItem(args, 2, PyLong_FromLong((long) current));
+ PyTuple_SetItem(args, 3, PyLong_FromLong((long) total));
+ if (dataarg) {
+ Py_INCREF(dataarg); /* Because GetItem doesn't give a ref but SetItem taketh away */
+ PyTuple_SetItem(args, 4, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, args);
+ if (PyErr_Occurred())
+ _pyme_stash_callback_exception(self);
+ Py_DECREF(args);
+ Py_XDECREF(retval);
+ PyGILState_Release(state);
+}
+
+PyObject *
+pyme_set_progress_cb(PyObject *self, PyObject *cb) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *wrapped;
+ gpgme_ctx_t ctx;
+
+ wrapped = PyObject_GetAttrString(self, "wrapped");
+ if (wrapped == NULL)
+ {
+ assert (PyErr_Occurred ());
+ PyGILState_Release(state);
+ return NULL;
+ }
+
+ ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
+ Py_DECREF(wrapped);
+ if (ctx == NULL)
+ {
+ if (cb == Py_None)
+ goto out;
+ else
+ return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
+ }
+
+ if (cb == Py_None) {
+ gpgme_set_progress_cb(ctx, NULL, NULL);
+ PyObject_SetAttrString(self, "_progress_cb", Py_None);
+ goto out;
+ }
+
+ if (! PyTuple_Check(cb))
+ return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
+ if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
+ return PyErr_Format(PyExc_TypeError,
+ "cb must be a tuple of size 2 or 3");
+
+ gpgme_set_progress_cb(ctx, (gpgme_progress_cb_t) pyProgressCb, (void *) cb);
+ PyObject_SetAttrString(self, "_progress_cb", cb);
+
+ out:
+ Py_INCREF(Py_None);
+ PyGILState_Release(state);
+ return Py_None;
+}
+
+/* Status callbacks. */
+static gpgme_error_t pyStatusCb(void *hook, const char *keyword,
+ const char *args) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ gpgme_error_t err = 0;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2 || PyTuple_Size(pyhook) == 3);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ if (PyTuple_Size(pyhook) == 3) {
+ dataarg = PyTuple_GetItem(pyhook, 2);
+ pyargs = PyTuple_New(3);
+ } else {
+ pyargs = PyTuple_New(2);
+ }
+
+ if (keyword)
+ PyTuple_SetItem(pyargs, 0, PyUnicode_DecodeUTF8(keyword, strlen (keyword),
+ "strict"));
+ else
+ {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(pyargs, 0, Py_None);
+ }
+ PyTuple_SetItem(pyargs, 1, PyUnicode_DecodeUTF8(args, strlen (args),
+ "strict"));
+ if (PyErr_Occurred()) {
+ err = gpg_error(GPG_ERR_GENERAL);
+ Py_DECREF(pyargs);
+ goto leave;
+ }
+
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 2, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ if (PyErr_Occurred())
+ err = _pyme_exception2code();
+ Py_DECREF(pyargs);
+ Py_XDECREF(retval);
+
+ leave:
+ if (err)
+ _pyme_stash_callback_exception(self);
+ PyGILState_Release(state);
+ return err;
+}
+
+PyObject *
+pyme_set_status_cb(PyObject *self, PyObject *cb) {
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *wrapped;
+ gpgme_ctx_t ctx;
+
+ wrapped = PyObject_GetAttrString(self, "wrapped");
+ if (wrapped == NULL)
+ {
+ assert (PyErr_Occurred ());
+ PyGILState_Release(state);
+ return NULL;
+ }
+
+ ctx = _pyme_unwrap_gpgme_ctx_t(wrapped);
+ Py_DECREF(wrapped);
+ if (ctx == NULL)
+ {
+ if (cb == Py_None)
+ goto out;
+ else
+ return PyErr_Format(PyExc_RuntimeError, "wrapped is NULL");
+ }
+
+ if (cb == Py_None) {
+ gpgme_set_status_cb(ctx, NULL, NULL);
+ PyObject_SetAttrString(self, "_status_cb", Py_None);
+ goto out;
+ }
+
+ if (! PyTuple_Check(cb))
+ return PyErr_Format(PyExc_TypeError, "cb must be a tuple");
+ if (PyTuple_Size(cb) != 2 && PyTuple_Size(cb) != 3)
+ return PyErr_Format(PyExc_TypeError,
+ "cb must be a tuple of size 2 or 3");
+
+ gpgme_set_status_cb(ctx, (gpgme_status_cb_t) pyStatusCb, (void *) cb);
+ PyObject_SetAttrString(self, "_status_cb", cb);
+
+ out:
+ Py_INCREF(Py_None);
+ PyGILState_Release(state);
+ return Py_None;
+}
+
+
+
+/* Interact callbacks. */
+gpgme_error_t
+_pyme_interact_cb(void *opaque, const char *keyword,
+ const char *args, int fd)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *func = NULL, *dataarg = NULL, *pyargs = NULL, *retval = NULL;
+ PyObject *py_keyword;
+ PyObject *pyopaque = (PyObject *) opaque;
+ gpgme_error_t err_status = 0;
+ PyObject *self = NULL;
+
+ _pyme_exception_init();
+
+ assert (PyTuple_Check(pyopaque));
+ assert (PyTuple_Size(pyopaque) == 2 || PyTuple_Size(pyopaque) == 3);
+ self = PyTuple_GetItem(pyopaque, 0);
+ func = PyTuple_GetItem(pyopaque, 1);
+ if (PyTuple_Size(pyopaque) == 3) {
+ dataarg = PyTuple_GetItem(pyopaque, 2);
+ pyargs = PyTuple_New(3);
+ } else {
+ pyargs = PyTuple_New(2);
+ }
+
+ if (keyword)
+ py_keyword = PyUnicode_FromString(keyword);
+ else
+ {
+ Py_INCREF(Py_None);
+ py_keyword = Py_None;
+ }
+
+ PyTuple_SetItem(pyargs, 0, py_keyword);
+ PyTuple_SetItem(pyargs, 1, PyUnicode_FromString(args));
+ if (dataarg) {
+ Py_INCREF(dataarg); /* Because GetItem doesn't give a ref but SetItem taketh away */
+ PyTuple_SetItem(pyargs, 2, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ err_status = _pyme_exception2code();
+ } else {
+ if (fd>=0 && retval && PyUnicode_Check(retval)) {
+ PyObject *encoded = NULL;
+ char *buffer;
+ Py_ssize_t size;
+
+ encoded = PyUnicode_AsUTF8String(retval);
+ if (encoded == NULL)
+ {
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+ if (PyBytes_AsStringAndSize(encoded, &buffer, &size) == -1)
+ {
+ Py_DECREF(encoded);
+ err_status = gpg_error(GPG_ERR_GENERAL);
+ goto leave;
+ }
+
+ if (write(fd, buffer, size) < 0) {
+ err_status = gpgme_error_from_syserror ();
+ _pyme_raise_exception (err_status);
+ }
+ if (! err_status && write(fd, "\n", 1) < 0) {
+ err_status = gpgme_error_from_syserror ();
+ _pyme_raise_exception (err_status);
+ }
+ Py_DECREF(encoded);
+ }
+ }
+ leave:
+ if (err_status)
+ _pyme_stash_callback_exception(self);
+
+ Py_XDECREF(retval);
+ PyGILState_Release(state);
+ return err_status;
+}
+
+
+
+/* Data callbacks. */
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle HOOK. Return the number of characters read, 0 on EOF
+ and -1 on error. If an error occurs, errno is set. */
+static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ ssize_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(2);
+ } else {
+ pyargs = PyTuple_New(1);
+ }
+
+ PyTuple_SetItem(pyargs, 0, PyLong_FromSize_t(size));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 1, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (! PyBytes_Check(retval)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected bytes from read callback, got %s",
+ retval->ob_type->tp_name);
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (PyBytes_Size(retval) > size) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %zu bytes from read callback, got %zu",
+ size, PyBytes_Size(retval));
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ memcpy(buffer, PyBytes_AsString(retval), PyBytes_Size(retval));
+ result = PyBytes_Size(retval);
+
+ leave:
+ Py_XDECREF(retval);
+ PyGILState_Release(state);
+ return result;
+}
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle HOOK. Return the number of characters written, or -1
+ on error. If an error occurs, errno is set. */
+static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ ssize_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 2);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(2);
+ } else {
+ pyargs = PyTuple_New(1);
+ }
+
+ PyTuple_SetItem(pyargs, 0, PyBytes_FromStringAndSize(buffer, size));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 1, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(retval))
+ result = PyInt_AsSsize_t(retval);
+ else
+#endif
+ if (PyLong_Check(retval))
+ result = PyLong_AsSsize_t(retval);
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "expected int from write callback, got %s",
+ retval->ob_type->tp_name);
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ }
+
+ leave:
+ Py_XDECREF(retval);
+ PyGILState_Release(state);
+ return result;
+}
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle HOOK to OFFSET, relativ to
+ WHENCE. Returns the new offset in bytes from the beginning of the
+ data object. */
+static off_t pyDataSeekCb(void *hook, off_t offset, int whence)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ off_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 3);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(3);
+ } else {
+ pyargs = PyTuple_New(2);
+ }
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+ PyTuple_SetItem(pyargs, 0, PyLong_FromLongLong((long long) offset));
+#else
+ PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) offset));
+#endif
+ PyTuple_SetItem(pyargs, 1, PyLong_FromLong((long) whence));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 2, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(retval))
+ result = PyInt_AsLong(retval);
+ else
+#endif
+ if (PyLong_Check(retval))
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+ result = PyLong_AsLongLong(retval);
+#else
+ result = PyLong_AsLong(retval);
+#endif
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "expected int from seek callback, got %s",
+ retval->ob_type->tp_name);
+ _pyme_stash_callback_exception(self);
+ result = -1;
+ }
+
+ leave:
+ Py_XDECREF(retval);
+ PyGILState_Release(state);
+ return result;
+}
+
+/* Close the data object with the handle HOOK. */
+static void pyDataReleaseCb(void *hook)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 4);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(1);
+ } else {
+ pyargs = PyTuple_New(0);
+ }
+
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 0, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_XDECREF(retval);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred())
+ _pyme_stash_callback_exception(self);
+ PyGILState_Release(state);
+}
+
+PyObject *
+pyme_data_new_from_cbs(PyObject *self,
+ PyObject *pycbs,
+ gpgme_data_t *r_data)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ static struct gpgme_data_cbs cbs = {
+ pyDataReadCb,
+ pyDataWriteCb,
+ pyDataSeekCb,
+ pyDataReleaseCb,
+ };
+ gpgme_error_t err;
+
+ if (! PyTuple_Check(pycbs))
+ return PyErr_Format(PyExc_TypeError, "pycbs must be a tuple");
+ if (PyTuple_Size(pycbs) != 5 && PyTuple_Size(pycbs) != 6)
+ return PyErr_Format(PyExc_TypeError,
+ "pycbs must be a tuple of size 5 or 6");
+
+ err = gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs);
+ if (err)
+ return _pyme_raise_exception(err);
+
+ PyObject_SetAttrString(self, "_data_cbs", pycbs);
+
+ Py_INCREF(Py_None);
+ PyGILState_Release(state);
+ return Py_None;
+}
+
+
+
+/* The assuan callbacks. */
+
+gpgme_error_t
+_pyme_assuan_data_cb (void *hook, const void *data, size_t datalen)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ gpgme_error_t err = 0;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *py_data = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ assert (PyCallable_Check(func));
+
+ py_data = PyBytes_FromStringAndSize(data, datalen);
+ if (py_data == NULL)
+ {
+ err = _pyme_exception2code();
+ goto leave;
+ }
+
+ retval = PyObject_CallFunctionObjArgs(func, py_data, NULL);
+ if (PyErr_Occurred())
+ err = _pyme_exception2code();
+ Py_DECREF(py_data);
+ Py_XDECREF(retval);
+
+ leave:
+ if (err)
+ _pyme_stash_callback_exception(self);
+ PyGILState_Release(state);
+ return err;
+}
+
+gpgme_error_t
+_pyme_assuan_inquire_cb (void *hook, const char *name, const char *args,
+ gpgme_data_t *r_data)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ gpgme_error_t err = 0;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *py_name = NULL;
+ PyObject *py_args = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ assert (PyCallable_Check(func));
+
+ py_name = PyUnicode_FromString(name);
+ if (py_name == NULL)
+ {
+ err = _pyme_exception2code();
+ goto leave;
+ }
+
+ py_args = PyUnicode_FromString(args);
+ if (py_args == NULL)
+ {
+ err = _pyme_exception2code();
+ goto leave;
+ }
+
+ retval = PyObject_CallFunctionObjArgs(func, py_name, py_args, NULL);
+ if (PyErr_Occurred())
+ err = _pyme_exception2code();
+ Py_XDECREF(retval);
+
+ /* FIXME: Returning data is not yet implemented. */
+ *r_data = NULL;
+
+ leave:
+ Py_XDECREF(py_name);
+ Py_XDECREF(py_args);
+ if (err)
+ _pyme_stash_callback_exception(self);
+ PyGILState_Release(state);
+ return err;
+}
+
+gpgme_error_t
+_pyme_assuan_status_cb (void *hook, const char *status, const char *args)
+{
+ PyGILState_STATE state = PyGILState_Ensure();
+ gpgme_error_t err = 0;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *py_status = NULL;
+ PyObject *py_args = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 2);
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ assert (PyCallable_Check(func));
+
+ py_status = PyUnicode_FromString(status);
+ if (py_status == NULL)
+ {
+ err = _pyme_exception2code();
+ goto leave;
+ }
+
+ py_args = PyUnicode_FromString(args);
+ if (py_args == NULL)
+ {
+ err = _pyme_exception2code();
+ goto leave;
+ }
+
+ retval = PyObject_CallFunctionObjArgs(func, py_status, py_args, NULL);
+ if (PyErr_Occurred())
+ err = _pyme_exception2code();
+ Py_XDECREF(retval);
+
+ leave:
+ Py_XDECREF(py_status);
+ Py_XDECREF(py_args);
+ if (err)
+ _pyme_stash_callback_exception(self);
+ PyGILState_Release(state);
+ return err;
+}
diff --git a/lang/python/helpers.h b/lang/python/helpers.h
new file mode 100644
index 0000000..9200f93
--- /dev/null
+++ b/lang/python/helpers.h
@@ -0,0 +1,39 @@
+/*
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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
+*/
+
+#include <gpgme.h>
+#include "Python.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#define write(fd, str, sz) {DWORD written; WriteFile((HANDLE) fd, str, sz, &written, 0);}
+#endif
+
+/* Flag specifying whether this is an in-tree build. */
+extern int pyme_in_tree_build;
+
+PyObject *pyme_raise_callback_exception(PyObject *self);
+
+PyObject *pyme_set_passphrase_cb(PyObject *self, PyObject *cb);
+PyObject *pyme_set_progress_cb(PyObject *self, PyObject *cb);
+PyObject *pyme_set_status_cb(PyObject *self, PyObject *cb);
+
+PyObject *pyme_data_new_from_cbs(PyObject *self, PyObject *pycbs,
+ gpgme_data_t *r_data);
diff --git a/lang/python/private.h b/lang/python/private.h
new file mode 100644
index 0000000..3a903c1
--- /dev/null
+++ b/lang/python/private.h
@@ -0,0 +1,54 @@
+/*
+ * 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/>.
+ */
+
+#include <gpgme.h>
+
+#ifndef _PYME_PRIVATE_H_
+#define _PYME_PRIVATE_H_
+
+/* GPGME glue. Implemented in helpers.c. */
+
+void _pyme_exception_init(void);
+gpgme_error_t _pyme_exception2code(void);
+
+PyObject *_pyme_obj2gpgme_t(PyObject *input, const char *objtype, int argnum);
+PyObject *_pyme_obj2gpgme_data_t(PyObject *input, int argnum,
+ gpgme_data_t *wrapper,
+ PyObject **bytesio, Py_buffer *view);
+
+PyObject *_pyme_wrap_result(PyObject *fragile, const char *classname);
+
+gpgme_error_t _pyme_interact_cb(void *opaque, const char *keyword,
+ const char *args, int fd);
+gpgme_error_t _pyme_assuan_data_cb (void *hook,
+ const void *data, size_t datalen);
+gpgme_error_t _pyme_assuan_inquire_cb (void *hook,
+ const char *name, const char *args,
+ gpgme_data_t *r_data);
+gpgme_error_t _pyme_assuan_status_cb (void *hook,
+ const char *status, const char *args);
+
+
+
+/* SWIG runtime support. Implemented in gpgme.i. */
+
+PyObject *_pyme_wrap_gpgme_data_t(gpgme_data_t data);
+gpgme_ctx_t _pyme_unwrap_gpgme_ctx_t(PyObject *wrapped);
+
+#endif /* _PYME_PRIVATE_H_ */
diff --git a/lang/python/pyme/__init__.py b/lang/python/pyme/__init__.py
new file mode 100644
index 0000000..12c96c2
--- /dev/null
+++ b/lang/python/pyme/__init__.py
@@ -0,0 +1,125 @@
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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
+
+"""Pyme: GPGME Interface for Python
+
+Welcome to PyME, the GPGME Interface for Python. "Pyme", when prounced,
+rhymes with "Pine".
+
+The latest release of this package may be obtained from
+https://www.gnupg.org
+
+Previous releases of this package for Python 2 can be obtained from
+http://pyme.sourceforge.net
+
+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 pyme
+ >>> with pyme.Context() as c:
+ >>> with pyme.Context() as c:
+ ... cipher, _, _ = c.encrypt("Hello world :)".encode(),
+ ... passphrase="abc")
+ ... c.decrypt(cipher, passphrase="abc")
+ ...
+ (b'Hello world :)',
+ <pyme.results.DecryptResult object at 0x7f5ab8121080>,
+ <pyme.results.VerifyResult object at 0x7f5ab81219b0>)
+
+GENERAL OVERVIEW
+----------------
+
+For those of you familiar with GPGME, you will be right at home here.
+
+Pyme 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 pyme.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
+--------------------
+PYME3 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/pyme/__pycache__/__init__.cpython-34.pyc b/lang/python/pyme/__pycache__/__init__.cpython-34.pyc
new file mode 100644
index 0000000..ba78937
--- /dev/null
+++ b/lang/python/pyme/__pycache__/__init__.cpython-34.pyc
Binary files differ
diff --git a/lang/python/pyme/__pycache__/version.cpython-34.pyc b/lang/python/pyme/__pycache__/version.cpython-34.pyc
new file mode 100644
index 0000000..658008a
--- /dev/null
+++ b/lang/python/pyme/__pycache__/version.cpython-34.pyc
Binary files differ
diff --git a/lang/python/pyme/callbacks.py b/lang/python/pyme/callbacks.py
new file mode 100644
index 0000000..b25a9a7
--- /dev/null
+++ b/lang/python/pyme/callbacks.py
@@ -0,0 +1,49 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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/pyme/constants/__init__.py b/lang/python/pyme/constants/__init__.py
new file mode 100644
index 0000000..96d89e4
--- /dev/null
+++ b/lang/python/pyme/constants/__init__.py
@@ -0,0 +1,114 @@
+
+from __future__ import absolute_import, print_function, unicode_literals
+del absolute_import, print_function, unicode_literals
+
+from pyme import util
+util.process_constants('GPGME_', globals())
+
+__all__ = ['data', 'event', 'import', 'keylist', 'md', 'pk',
+ 'protocol', 'sig', 'sigsum', 'status', 'validity']
+
+# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact. We
+# implement pyme.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/pyme/constants/data/__init__.py b/lang/python/pyme/constants/data/__init__.py
new file mode 100644
index 0000000..8274ab9
--- /dev/null
+++ b/lang/python/pyme/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/pyme/constants/data/encoding.py b/lang/python/pyme/constants/data/encoding.py
new file mode 100644
index 0000000..a05dbb4
--- /dev/null
+++ b/lang/python/pyme/constants/data/encoding.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_DATA_ENCODING_', globals())
diff --git a/lang/python/pyme/constants/event.py b/lang/python/pyme/constants/event.py
new file mode 100644
index 0000000..2e30c5e
--- /dev/null
+++ b/lang/python/pyme/constants/event.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_EVENT_', globals())
diff --git a/lang/python/pyme/constants/import.py b/lang/python/pyme/constants/import.py
new file mode 100644
index 0000000..10e7d3c
--- /dev/null
+++ b/lang/python/pyme/constants/import.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_IMPORT_', globals())
diff --git a/lang/python/pyme/constants/keylist/__init__.py b/lang/python/pyme/constants/keylist/__init__.py
new file mode 100644
index 0000000..2ce0edf
--- /dev/null
+++ b/lang/python/pyme/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/pyme/constants/keylist/mode.py b/lang/python/pyme/constants/keylist/mode.py
new file mode 100644
index 0000000..000dd79
--- /dev/null
+++ b/lang/python/pyme/constants/keylist/mode.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_KEYLIST_MODE_', globals())
diff --git a/lang/python/pyme/constants/md.py b/lang/python/pyme/constants/md.py
new file mode 100644
index 0000000..dbd762c
--- /dev/null
+++ b/lang/python/pyme/constants/md.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_MD_', globals())
diff --git a/lang/python/pyme/constants/pk.py b/lang/python/pyme/constants/pk.py
new file mode 100644
index 0000000..cfc5309
--- /dev/null
+++ b/lang/python/pyme/constants/pk.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_PK_', globals())
diff --git a/lang/python/pyme/constants/protocol.py b/lang/python/pyme/constants/protocol.py
new file mode 100644
index 0000000..a4b6583
--- /dev/null
+++ b/lang/python/pyme/constants/protocol.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_PROTOCOL_', globals())
diff --git a/lang/python/pyme/constants/sig/__init__.py b/lang/python/pyme/constants/sig/__init__.py
new file mode 100644
index 0000000..2ce0edf
--- /dev/null
+++ b/lang/python/pyme/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
+__all__ = ['mode']
diff --git a/lang/python/pyme/constants/sig/mode.py b/lang/python/pyme/constants/sig/mode.py
new file mode 100644
index 0000000..fb534bc
--- /dev/null
+++ b/lang/python/pyme/constants/sig/mode.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_SIG_MODE_', globals())
diff --git a/lang/python/pyme/constants/sigsum.py b/lang/python/pyme/constants/sigsum.py
new file mode 100644
index 0000000..3d94745
--- /dev/null
+++ b/lang/python/pyme/constants/sigsum.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_SIGSUM_', globals())
diff --git a/lang/python/pyme/constants/status.py b/lang/python/pyme/constants/status.py
new file mode 100644
index 0000000..a04d9aa
--- /dev/null
+++ b/lang/python/pyme/constants/status.py
@@ -0,0 +1,124 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme.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/pyme/constants/validity.py b/lang/python/pyme/constants/validity.py
new file mode 100644
index 0000000..4ecd4d3
--- /dev/null
+++ b/lang/python/pyme/constants/validity.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 pyme import util
+util.process_constants('GPGME_VALIDITY_', globals())
diff --git a/lang/python/pyme/core.py b/lang/python/pyme/core.py
new file mode 100644
index 0000000..88a086b
--- /dev/null
+++ b/lang/python/pyme/core.py
@@ -0,0 +1,1145 @@
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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.pyme_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.pyme_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):
+ """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)
+
+ """
+ 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
+
+ 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):
+ """List keys
+
+ Keyword arguments:
+ pattern -- return keys matching pattern (default: all keys)
+ secret -- return only secret keys
+
+ Returns:
+ -- an iterator returning key objects
+
+ Raises:
+ GPGMEError -- as signaled by the underlying library
+ """
+ return self.op_keylist_all(pattern, secret)
+
+ 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 isinstance(command, (str, 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.pyme_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.pyme_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)
+
+ _ctype = 'gpgme_ctx_t'
+ _cprefix = 'gpgme_'
+
+ def _errorcheck(self, name):
+ """This function should list all functions returning gpgme_error_t"""
+ return ((name.startswith('gpgme_op_')
+ and not name.endswith('_result'))
+ or name in {
+ 'gpgme_set_ctx_flag',
+ 'gpgme_set_protocol',
+ 'gpgme_set_sub_protocol',
+ 'gpgme_set_keylist_mode',
+ 'gpgme_set_pinentry_mode',
+ 'gpgme_set_locale',
+ 'gpgme_set_engine_info',
+ 'gpgme_signers_add',
+ 'gpgme_get_sig_key',
+ 'gpgme_sig_notation_add',
+ 'gpgme_cancel',
+ 'gpgme_cancel_async',
+ 'gpgme_cancel_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):
+ """Return the key corresponding to the fingerprint 'fpr'"""
+ ptr = gpgme.new_gpgme_key_t_p()
+ errorcheck(gpgme.gpgme_get_key(self.wrapped, fpr, ptr, secret))
+ key = gpgme.gpgme_key_t_p_value(ptr)
+ gpgme.delete_gpgme_key_t_p(ptr)
+ if 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.pyme_set_passphrase_cb(self, hookdata)
+
+ def _free_passcb(self):
+ if gpgme.pyme_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.pyme_set_progress_cb(self, hookdata)
+
+ def _free_progresscb(self):
+ if gpgme.pyme_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.pyme_set_status_cb(self, hookdata)
+
+ def _free_statuscb(self):
+ if gpgme.pyme_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)
+
+ """
+ errorcheck(gpgme.gpgme_ctx_set_engine_info(
+ self.wrapped, 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"""
+ return name not in {
+ 'gpgme_data_release_and_get_mem',
+ 'gpgme_data_get_encoding',
+ 'gpgme_data_seek',
+ 'gpgme_data_get_file_name',
+ }
+
+ 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.pyme_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.pyme_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.pyme_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.pyme_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.pyme_raise_callback_exception(self)
+ else:
+ raise
+ if len(result) == 0:
+ break
+ chunks.append(result)
+ return b''.join(chunks)
+
+def pubkey_algo_name(algo):
+ return gpgme.gpgme_pubkey_algo_name(algo)
+
+def hash_algo_name(algo):
+ return gpgme.gpgme_hash_algo_name(algo)
+
+def get_protocol_name(proto):
+ return gpgme.gpgme_get_protocol_name(proto)
+
+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/pyme/errors.py b/lang/python/pyme/errors.py
new file mode 100644
index 0000000..e26c747
--- /dev/null
+++ b/lang/python/pyme/errors.py
@@ -0,0 +1,111 @@
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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
+
+util.process_constants('GPG_ERR_', globals())
+
+# To appease static analysis tools, we define some constants here:
+NO_ERROR = 0
+
+class PymeError(Exception):
+ pass
+
+class GPGMEError(PymeError):
+ 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)
+
+# These errors are raised in the idiomatic interface code.
+
+class EncryptionError(PymeError):
+ 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(PymeError):
+ pass
+
+class UnsupportedAlgorithm(DeryptionError):
+ def __init__(self, algorithm):
+ self.algorithm = algorithm
+ def __str__(self):
+ return self.algorithm
+
+class SigningError(PymeError):
+ 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(PymeError):
+ 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/pyme/gpgme.py b/lang/python/pyme/gpgme.py
new file mode 100644
index 0000000..ea4983d
--- /dev/null
+++ b/lang/python/pyme/gpgme.py
@@ -0,0 +1,125 @@
+# This file was automatically generated by SWIG (http://www.swig.org).
+# Version 3.0.7
+#
+# Do not make changes to this file unless you know what you are doing--modify
+# the SWIG interface file instead.
+
+
+
+
+
+from sys import version_info
+if version_info >= (2, 6, 0):
+ def swig_import_helper():
+ from os.path import dirname
+ import imp
+ fp = None
+ try:
+ fp, pathname, description = imp.find_module('_gpgme', [dirname(__file__)])
+ except ImportError:
+ import _gpgme
+ return _gpgme
+ if fp is not None:
+ try:
+ _mod = imp.load_module('_gpgme', fp, pathname, description)
+ finally:
+ fp.close()
+ return _mod
+ _gpgme = swig_import_helper()
+ del swig_import_helper
+else:
+ import _gpgme
+del version_info
+from _gpgme import *
+try:
+ _swig_property = property
+except NameError:
+ pass # Python < 2.2 doesn't have 'property'.
+
+
+def _swig_setattr_nondynamic(self, class_type, name, value, static=1):
+ if (name == "thisown"):
+ return self.this.own(value)
+ if (name == "this"):
+ if type(value).__name__ == 'SwigPyObject':
+ self.__dict__[name] = value
+ return
+ method = class_type.__swig_setmethods__.get(name, None)
+ if method:
+ return method(self, value)
+ if (not static):
+ if _newclass:
+ object.__setattr__(self, name, value)
+ else:
+ self.__dict__[name] = value
+ else:
+ raise AttributeError("You cannot add attributes to %s" % self)
+
+
+def _swig_setattr(self, class_type, name, value):
+ return _swig_setattr_nondynamic(self, class_type, name, value, 0)
+
+
+def _swig_getattr_nondynamic(self, class_type, name, static=1):
+ if (name == "thisown"):
+ return self.this.own()
+ method = class_type.__swig_getmethods__.get(name, None)
+ if method:
+ return method(self)
+ if (not static):
+ return object.__getattr__(self, name)
+ else:
+ raise AttributeError(name)
+
+def _swig_getattr(self, class_type, name):
+ return _swig_getattr_nondynamic(self, class_type, name, 0)
+
+
+def _swig_repr(self):
+ try:
+ strthis = "proxy of " + self.this.__repr__()
+ except:
+ strthis = ""
+ return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
+
+try:
+ _object = object
+ _newclass = 1
+except AttributeError:
+ class _object:
+ pass
+ _newclass = 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# This file is compatible with both classic and new-style classes.
+
+
diff --git a/lang/python/pyme/results.py b/lang/python/pyme/results.py
new file mode 100644
index 0000000..3383896
--- /dev/null
+++ b/lang/python/pyme/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 __str__(self):
+ return '<{} {}>'.format(
+ self.__class__.__name__,
+ ', '.join('{}: {}'.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/pyme/util.py b/lang/python/pyme/util.py
new file mode 100644
index 0000000..e4fca4c
--- /dev/null
+++ b/lang/python/pyme/util.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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/pyme/version.py b/lang/python/pyme/version.py
new file mode 100644
index 0000000..21a0122
--- /dev/null
+++ b/lang/python/pyme/version.py
@@ -0,0 +1,68 @@
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2015 Ben McGinnes <ben@adversary.org>
+# Copyright (C) 2004 Igor Belyi <belyi@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 = 'pyme'
+versionstr = "1.7.0"
+gpgme_versionstr = gpgme.GPGME_VERSION
+in_tree_build = bool(gpgme.cvar.pyme_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@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@adversary.org>
+Copyright (C) 2014, 2015 Martin Albrecht <martinralbrecht@googlemail.com>
+Copyright (C) 2004, 2008 Igor Belyi <belyi@users.sourceforge.net>
+Copyright (C) 2002 John Goerzen <jgoerzen@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/pyme/version.py.in b/lang/python/pyme/version.py.in
new file mode 100644
index 0000000..cfb9510
--- /dev/null
+++ b/lang/python/pyme/version.py.in
@@ -0,0 +1,68 @@
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2015 Ben McGinnes <ben@adversary.org>
+# Copyright (C) 2004 Igor Belyi <belyi@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 = 'pyme'
+versionstr = "@VERSION@"
+gpgme_versionstr = gpgme.GPGME_VERSION
+in_tree_build = bool(gpgme.cvar.pyme_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@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@adversary.org>
+Copyright (C) 2014, 2015 Martin Albrecht <martinralbrecht@googlemail.com>
+Copyright (C) 2004, 2008 Igor Belyi <belyi@users.sourceforge.net>
+Copyright (C) 2002 John Goerzen <jgoerzen@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
new file mode 100755
index 0000000..31892c1
--- /dev/null
+++ b/lang/python/setup.py.in
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2016 g10 Code GmbH
+# Copyright (C) 2004 Igor Belyi <belyi@users.sourceforge.net>
+# Copyright (C) 2002 John Goerzen <jgoerzen@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 distutils.core import setup, Extension
+import os, os.path, sys
+import glob
+import subprocess
+
+# Out-of-tree build of the pyme3 bindings.
+gpg_error_config = ["gpg-error-config"]
+gpgme_config_flags = ["--thread=pthread"]
+gpgme_config = ["gpgme-config"] + gpgme_config_flags
+gpgme_h = ""
+library_dirs = []
+in_tree = False
+extra_swig_opts = []
+extra_macros = dict()
+
+if os.path.exists("../../src/gpgme-config"):
+ # 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
+ extra_macros.update(
+ HAVE_DATA_H=1,
+ IN_TREE_BUILD=1,
+ )
+
+if hasattr(subprocess, "DEVNULL"):
+ devnull = 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)
+except:
+ sys.exit("Could not find gpgme-config. " +
+ "Please install the libgpgme development package.")
+
+def getconfig(what, config=gpgme_config):
+ confdata = subprocess.Popen(config + ["--%s" % what],
+ stdout=subprocess.PIPE).communicate()[0]
+ return [x for x in confdata.decode('utf-8').split() if x != '']
+
+version = version_raw = getconfig("version")[0]
+if '-' in version:
+ version = version.split('-')[0]
+major, minor, patch = map(int, version.split('.'))
+
+if not (major > 1 or (major == 1 and minor >= 6)):
+ sys.exit('Need at least GPGME version 1.6, found {}.'.format(version_raw))
+
+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]
+
+print("Building pyme3 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"))
+
+include_dirs = [os.getcwd()]
+define_macros = []
+libs = getconfig('libs')
+
+# Define extra_macros for both the SWIG and C code
+for k, v in extra_macros.items():
+ extra_swig_opts.append("-D{0}={1}".format(k, v))
+ define_macros.append((k, str(v)))
+
+for item in getconfig('cflags'):
+ if item.startswith("-I"):
+ include_dirs.append(item[2:])
+ elif item.startswith("-D"):
+ defitem = item[2:].split("=", 1)
+ if len(defitem)==2:
+ define_macros.append((defitem[0], defitem[1]))
+ else:
+ define_macros.append((defitem[0], None))
+
+# Adjust include and library locations in case of win32
+uname_s = os.popen("uname -s").read()
+if uname_s.startswith("MINGW32"):
+ mnts = [x.split()[0:3:2] for x in os.popen("mount").read().split("\n") if x]
+ tmplist = sorted([(len(x[1]), x[1], x[0]) for x in mnts])
+ tmplist.reverse()
+ extra_dirs = []
+ for item in include_dirs:
+ for ln, mnt, tgt in tmplist:
+ if item.startswith(mnt):
+ item = os.path.normpath(item[ln:])
+ while item[0] == os.path.sep:
+ item = item[1:]
+ extra_dirs.append(os.path.join(tgt, item))
+ break
+ include_dirs += extra_dirs
+ for item in [x[2:] for x in libs if x.startswith("-L")]:
+ for ln, mnt, tgt in tmplist:
+ if item.startswith(mnt):
+ item = os.path.normpath(item[ln:])
+ while item[0] == os.path.sep:
+ item = item[1:]
+ library_dirs.append(os.path.join(tgt, item))
+ break
+
+# 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
+# directory.
+# Bug: http://bugs.python.org/issue1016626
+# Workaround:
+# http://stackoverflow.com/questions/12491328/python-distutils-not-include-the-swig-generated-module
+from distutils.command.build import build
+class BuildExtFirstHack(build):
+ def run(self):
+ self.run_command('build_ext')
+ build.run(self)
+
+swige = Extension("pyme._gpgme", ["gpgme.i", "helpers.c"],
+ swig_opts = ['-py3', '-builtin', '-threads',
+ '-outdir', 'pyme'] + extra_swig_opts,
+ include_dirs = include_dirs,
+ define_macros = define_macros,
+ library_dirs = library_dirs,
+ extra_link_args = libs)
+
+setup(name="pyme3",
+ cmdclass={'build': BuildExtFirstHack},
+ version="@VERSION@",
+ description='Python bindings for GPGME GnuPG cryptography library',
+ # XXX add a long description
+ #long_description=long_description,
+ author='The GnuPG hackers',
+ author_email='gnupg-devel@gnupg.org',
+ url='https://www.gnupg.org',
+ ext_modules=[swige],
+ packages = ['pyme', 'pyme.constants', 'pyme.constants.data',
+ 'pyme.constants.keylist', 'pyme.constants.sig'],
+ license="LGPL2.1+ (the library), GPL2+ (tests and examples)",
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
+ 'Programming Language :: Python :: 3.6',
+ 'Operating System :: POSIX',
+ 'Operating System :: Microsoft :: Windows',
+ 'Topic :: Communications :: Email',
+ 'Topic :: Security :: Cryptography',
+ ],
+)
diff --git a/lang/python/tests/Makefile.am b/lang/python/tests/Makefile.am
new file mode 100644
index 0000000..aa88bdc
--- /dev/null
+++ b/lang/python/tests/Makefile.am
@@ -0,0 +1,114 @@
+# Makefile.am for the tests of the Python bindings.
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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/>.
+
+GPG = gpg
+GPG_AGENT = gpg-agent
+export GNUPGHOME := $(abs_builddir)
+export GPG_AGENT_INFO :=
+
+test_srcdir = $(top_srcdir)/tests/gpg
+
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) \
+ LC_ALL=C GPG_AGENT_INFO= \
+ top_srcdir=$(top_srcdir) \
+ srcdir=$(srcdir) \
+ LD_LIBRARY_PATH="../../../src/.libs:$(LD_LIBRARY_PATH)"
+
+py_tests = t-wrapper.py \
+ t-callbacks.py \
+ t-data.py \
+ t-encrypt.py \
+ t-encrypt-sym.py \
+ t-encrypt-sign.py \
+ t-sign.py \
+ t-signers.py \
+ t-decrypt.py \
+ t-verify.py \
+ t-decrypt-verify.py \
+ t-sig-notation.py \
+ t-export.py \
+ t-import.py \
+ t-trustlist.py \
+ t-edit.py \
+ t-keylist.py \
+ t-wait.py \
+ t-encrypt-large.py \
+ t-file-name.py \
+ t-idiomatic.py \
+ t-protocol-assuan.py
+
+XTESTS = initial.py $(py_tests) final.py
+EXTRA_DIST = support.py $(XTESTS) encrypt-only.asc sign-only.asc \
+ run-tests.py
+
+# XXX: Currently, one cannot override automake's 'check' target. As a
+# workaround, we avoid defining 'TESTS', thus automake will not emit
+# the 'check' target. For extra robustness, we merely define a
+# dependency on 'xcheck', so this hack should also work even if
+# automake would emit the 'check' target, as adding dependencies to
+# targets is okay.
+check: xcheck
+
+.PHONY: xcheck
+
+xcheck: ./pubring-stamp
+ $(TESTS_ENVIRONMENT) $(PYTHON) $(srcdir)/run-tests.py \
+ --interpreters="$(PYTHONS)" --srcdir=$(srcdir) $(TESTFLAGS) \
+ $(XTESTS)
+
+CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
+ gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \
+ random_seed .gpg-v21-migrated \
+ pubring-stamp private-keys-v1.d/gpg-sample.stamp
+
+private_keys = \
+ $(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
+ $(test_srcdir)/76F7E2B35832976B50A27A282D9B87E44577EB66 \
+ $(test_srcdir)/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \
+ $(test_srcdir)/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F \
+ $(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C
+
+clean-local:
+ -$(top_srcdir)/tests/start-stop-agent --stop
+ -rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol
+
+
+./private-keys-v1.d/gpg-sample.stamp: $(private_keys)
+ test -d ./private-keys-v1.d || mkdir ./private-keys-v1.d
+ for k in $(private_keys); do \
+ cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \
+ done
+ 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
+ -$(GPG) --batch --no-permission-warning \
+ --import $(test_srcdir)/secdemo.asc
+ echo x > ./pubring-stamp
+
+./gpg.conf:
+# This is required for t-sig-notations.
+ echo no-force-v3-sigs > ./gpg.conf
+
+./gpg-agent.conf:
+# This is required for gpg2, which does not support command fd.
+ echo pinentry-program $(abs_top_srcdir)/tests/gpg/pinentry >$@
+ echo allow-loopback-pinentry >>$@
diff --git a/lang/python/tests/Makefile.in b/lang/python/tests/Makefile.in
new file mode 100644
index 0000000..3886bf4
--- /dev/null
+++ b/lang/python/tests/Makefile.in
@@ -0,0 +1,620 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for the tests of the Python bindings.
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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/>.
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/python/tests
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GPG = gpg
+GPG_AGENT = gpg-agent
+test_srcdir = $(top_srcdir)/tests/gpg
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) \
+ LC_ALL=C GPG_AGENT_INFO= \
+ top_srcdir=$(top_srcdir) \
+ srcdir=$(srcdir) \
+ LD_LIBRARY_PATH="../../../src/.libs:$(LD_LIBRARY_PATH)"
+
+py_tests = t-wrapper.py \
+ t-callbacks.py \
+ t-data.py \
+ t-encrypt.py \
+ t-encrypt-sym.py \
+ t-encrypt-sign.py \
+ t-sign.py \
+ t-signers.py \
+ t-decrypt.py \
+ t-verify.py \
+ t-decrypt-verify.py \
+ t-sig-notation.py \
+ t-export.py \
+ t-import.py \
+ t-trustlist.py \
+ t-edit.py \
+ t-keylist.py \
+ t-wait.py \
+ t-encrypt-large.py \
+ t-file-name.py \
+ t-idiomatic.py \
+ t-protocol-assuan.py
+
+XTESTS = initial.py $(py_tests) final.py
+EXTRA_DIST = support.py $(XTESTS) encrypt-only.asc sign-only.asc \
+ run-tests.py
+
+CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
+ gpg-agent.conf pubring.kbx~ gpg.conf pubring.gpg~ \
+ random_seed .gpg-v21-migrated \
+ pubring-stamp private-keys-v1.d/gpg-sample.stamp
+
+private_keys = \
+ $(test_srcdir)/13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \
+ $(test_srcdir)/76F7E2B35832976B50A27A282D9B87E44577EB66 \
+ $(test_srcdir)/A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD \
+ $(test_srcdir)/13CBE3758AFE42B5E5E2AE4CED27AFA455E3F87F \
+ $(test_srcdir)/7A030357C0F253A5BBCD282FFC4E521B37558F5C
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/python/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/python/tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ clean-local cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+export GNUPGHOME := $(abs_builddir)
+export GPG_AGENT_INFO :=
+
+# XXX: Currently, one cannot override automake's 'check' target. As a
+# workaround, we avoid defining 'TESTS', thus automake will not emit
+# the 'check' target. For extra robustness, we merely define a
+# dependency on 'xcheck', so this hack should also work even if
+# automake would emit the 'check' target, as adding dependencies to
+# targets is okay.
+check: xcheck
+
+.PHONY: xcheck
+
+xcheck: ./pubring-stamp
+ $(TESTS_ENVIRONMENT) $(PYTHON) $(srcdir)/run-tests.py \
+ --interpreters="$(PYTHONS)" --srcdir=$(srcdir) $(TESTFLAGS) \
+ $(XTESTS)
+
+clean-local:
+ -$(top_srcdir)/tests/start-stop-agent --stop
+ -rm -fR -- private-keys-v1.d openpgp-revocs.d S.gpg-agent sshcontrol
+
+./private-keys-v1.d/gpg-sample.stamp: $(private_keys)
+ test -d ./private-keys-v1.d || mkdir ./private-keys-v1.d
+ for k in $(private_keys); do \
+ cp $$k private-keys-v1.d/$${k#$(test_srcdir)/}.key; \
+ done
+ 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
+ -$(GPG) --batch --no-permission-warning \
+ --import $(test_srcdir)/secdemo.asc
+ echo x > ./pubring-stamp
+
+./gpg.conf:
+# This is required for t-sig-notations.
+ echo no-force-v3-sigs > ./gpg.conf
+
+./gpg-agent.conf:
+# This is required for gpg2, which does not support command fd.
+ echo pinentry-program $(abs_top_srcdir)/tests/gpg/pinentry >$@
+ echo allow-loopback-pinentry >>$@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/python/tests/encrypt-only.asc b/lang/python/tests/encrypt-only.asc
new file mode 100644
index 0000000..6e068a0
--- /dev/null
+++ b/lang/python/tests/encrypt-only.asc
@@ -0,0 +1,33 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v2
+
+lQPGBFd/jL0BCAD8jfoblIrlHS0shDCbSiO7RFaT6sEa/6tSPkv6XzBba9oXOkuO
+FLTkNpIwPb92U8SOS+27j7n9v6U5NW2tyZwIoeLb8lUyKnCBr22IUhTFVXf7fros
+zmPugsJaDBi9f7RL0bqiCn4EV3DGKyAukZklk1k1JV4Ec3dEPMAmL9LmnvXreEjU
+pQZZN9sJV32ew8CYkZ6AB8foFQwfxn4x0iUoKvj8kW9RsY1KMPucp4YiFhHeMZW1
+5wGAZdEIZYKyWEp4bi/wC9yn/TUR5uNWc0uVJzQvuHwaYjolPW89DinjBkPEJCBr
+RwumaOWfbu/hb51wBoUTmUr9diVw93L2ROLPABEBAAH+BwMC1bmUAoPJKI/WBiHm
+P6tSNRLdd+7etfjAFvKL7Ob2pNTrc3hbtyOLIQ9tuEaqXEyfnCms/DCg8QdkaFUv
+Nkoj0W5+G/MQuR2jIvrq/wyL/4jIw0AFbp9/V1JbSXZh2g1eJLnnykn7uPxCbDFY
+FrVeFmkhoxZ3pid6ZQSWlxXsdW+YMvbUfNIIZpbygI/alIBvbDS1YJYEBDCwFZjU
+7quE2Ufxo8dm34EHcmbpYpn4r3DUrU5AHQ2fIprLIVqHn4+NUrR8WZS9nCnIeu/z
+OaJUZ2lJFRjUC6Gpsbsw6Xwh4Ntwzyt2SsXc+UVZngjozw3yw0VpDifxMBqcd+9x
+baSc7dfbOZF2BCZOwnB7/QrFZDaqe5b3n6rTdj1va/CrJMuxbgaNAjvLpdT2EUPZ
+fHDAdPAjASofxBREv+HIKwksuPJ9cvavZU6Q4KQA7buo25hd7yjuba4WbLQhp0jH
+AT1P7SdakMhk/IFcUKFdB3ZyZZZ1JTTPa2xZn9yDa3Jb1t7IMLYLwY6EFbjvaxH5
+WEGZvOAq2iEa941mxv4miwgf7MQPx6g9u0+dXc7iZApwWs9MNfJo3J25sKhWK5Be
+Bu3w7c6nrlg40GtPuDRgaBvYWbVerJcepTA/EPfugEJtRsDJkt7wZq1H9lWHU7Ih
+Up6/+XKtBzlCIqYjorzFLnC721pcKFcPhLgvtjjNJvUsLXbr9CwnBub/eTFcfRb2
+ro60H9cOhf0fQSQyvkZWfzq0BN6rG27G1KhyprsJAmpW0fTHHkB4V19788C2sTQv
+D93VU3Nd6MWocwAYtPWmtwXPpuOAU9IcwAvVTxBeBJCXxbH3uyx1frwDXA7lf4Pb
+a8hMoMMVU+rAG1uepKI5h4seBIKP7qKEKAPloI6/Vtf7/Ump4DKprS1QpfOW+lsX
+aR48lgNR6sQXtDdFbmNyeXB0aW9uIE9ubHkgKHRlc3Qga2V5LCBkbyBub3QgdXNl
+KSA8ZW9AZXhhbXBsZS5vcmc+iQE3BBMBCAAhBQJXf4y9AhsNBQsJCAcCBhUICQoL
+AgQWAgMBAh4BAheAAAoJEJIFcnabn+Gc/KgH/07wzrsBzTqdI5L6cIqQ81Vq8ASj
+tsuYoVfFxymB8F/AxpnLMhYRuWQTcoUHQ/olG2yA0C6o4e1JPAmh6LQGwr0eRnc2
+2tr4cbnQAhXpJ8xOR6kH9eE8nGeC7tlEeeV/Wnj3SLZOXOjYjnA9bA3JX9DP3qcz
+w1sKQPEHsGkMJuT0ZadnlJ1qw8AnnNKLDlG4kIO9hz3qB8BjxFZf+j5f/nhFNv5I
+pnNdMcDwQqHVrwD6WO+Xmmdykab0awL9To0S9DG9ohcXuJiTMa8vtXFSBM0koUDk
+BWajEq+QAcDpmdFsQr4/gbzvHkAIVTQb0seJr4gpmXFZu3TMuGVD9j13GaI=
+=38ri
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/lang/python/tests/final.py b/lang/python/tests/final.py
new file mode 100755
index 0000000..8e7ab33
--- /dev/null
+++ b/lang/python/tests/final.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+import subprocess
+
+subprocess.check_call([os.path.join(os.getenv('top_srcdir'),
+ "tests", "start-stop-agent"), "--stop"])
diff --git a/lang/python/tests/initial.py b/lang/python/tests/initial.py
new file mode 100755
index 0000000..2d4827a
--- /dev/null
+++ b/lang/python/tests/initial.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+import subprocess
+import pyme
+import support
+support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP)
+
+subprocess.check_call([os.path.join(os.getenv('top_srcdir'),
+ "tests", "start-stop-agent"), "--start"])
+
+with pyme.Context() as c:
+ alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)
+ bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)
+
+ # Mark alpha as trusted. The signature verification tests expect
+ # this.
+ support.mark_key_trusted(c, alpha)
+
+ c.op_import(open(support.in_srcdir("encrypt-only.asc")))
+ c.op_import(open(support.in_srcdir("sign-only.asc")))
diff --git a/lang/python/tests/run-tests.py b/lang/python/tests/run-tests.py
new file mode 100644
index 0000000..55d3f11
--- /dev/null
+++ b/lang/python/tests/run-tests.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+import argparse
+import glob
+import os
+import subprocess
+import sys
+
+class SplitAndAccumulate(argparse.Action):
+ def __call__(self, parser, namespace, values, option_string=None):
+ current = getattr(namespace, self.dest, list())
+ current.extend(values.split())
+ setattr(namespace, self.dest, current)
+
+parser = argparse.ArgumentParser(description='Run tests.')
+parser.add_argument('tests', metavar='TEST', type=str, nargs='+',
+ help='A test to run')
+parser.add_argument('-v', '--verbose', action="store_true", default=False,
+ help='Be verbose.')
+parser.add_argument('--interpreters', metavar='PYTHON', type=str,
+ default=[], action=SplitAndAccumulate,
+ help='Use these interpreters to run the tests, ' +
+ 'separated by spaces.')
+parser.add_argument('--srcdir', type=str,
+ default=os.environ.get("srcdir", ""),
+ help='Location of the tests.')
+parser.add_argument('--builddir', type=str,
+ default=os.environ.get("abs_builddir", ""),
+ help='Location of the tests.')
+
+args = parser.parse_args()
+if not args.interpreters:
+ args.interpreters = [sys.executable]
+
+out = sys.stdout if args.verbose else None
+err = sys.stderr if args.verbose else None
+
+def status_to_str(code):
+ return {0: "PASS", 77: "SKIP", 99: "ERROR"}.get(code, "FAIL")
+
+results = list()
+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()
+
+ builddirs = glob.glob(os.path.join(args.builddir, "..", "build",
+ "lib*"+version))
+ assert len(builddirs) == 1, \
+ "Expected one build directory, got {0}".format(builddirs)
+ env = dict(os.environ)
+ env["PYTHONPATH"] = builddirs[0]
+
+ print("Running tests using {0} ({1})...".format(interpreter, version))
+ for test in args.tests:
+ status = subprocess.call(
+ [interpreter, os.path.join(args.srcdir, test)],
+ env=env, stdout=out, stderr=err)
+ print("{0}: {1}".format(status_to_str(status), test))
+ results.append(status)
+
+def count(status):
+ return len(list(filter(lambda x: x == status, results)))
+def failed():
+ return len(list(filter(lambda x: x not in (0, 77, 99), results)))
+
+print("{0} tests run, {1} succeeded, {2} failed, {3} skipped.".format(
+ len(results), count(0), failed(), count(77)))
+sys.exit(len(results) - count(0))
diff --git a/lang/python/tests/sign-only.asc b/lang/python/tests/sign-only.asc
new file mode 100644
index 0000000..6e2a6f3
--- /dev/null
+++ b/lang/python/tests/sign-only.asc
@@ -0,0 +1,33 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v2
+
+lQPFBFd/jO8BCADiull4EVJiKmJqclPyU6GhTlbJXw7Ch0zbFAauOWYT3ACmgr1U
+KfJlZ2sPe2EezZkVSACxgIjTCzcgKQLh/swXdhO8uEgWEIN8f07WcSVDrcRGYwDS
+KFSRsK0bfO/OQQDUsSkNQSHjcOdLnCHCinMrQi1mBZOs+Y/DXOkkEV1zbFFV7q6X
+4vX9HSWwTRQTdOV9CFZykbwM+X1YIZlVtpOAKqSNJi3P17uQF7P9zko6HWKKKQ5S
+96BfXUOIpBRl82R85/yQgeGrWlvZ2BT2ittscNQlBKqLHJ7LIeDr9ctbKlKZjHTn
+Da7NYg+PoMHspbizjSONbEzpcR/9ZUq16oJJABEBAAH+BwMC7hQZNJSmlX/W6sfL
+0wakX6kTsiCEMy2vMCRcZ769JKT234avHtkL/g7MBJEzqdG9HSEp7+LHGuOWJhfa
+20f61WvPT5ujUIy//QXJ9a8z877jCm+fHKCTDXGYLLfCkJLfr3/GfTRy6gaIGTSw
+BqZaRelPvHbMp+eiFqDkf8W/E1LO3/83k87+pXggjz4p0OasyMw8RcDmy+IKBMGG
+bzet5WIKHIhpblIzuuucQHOjtwA8vCedub3F4lcRuULe2GW6sNuCB9kjSC9g6D1d
+bJ+WYi5GiUUQARGSNXiWVoVPLpEo0i6/2bKJ7vBYGRewNp42ebVQU2bFW7uzhaIq
+4itzNTjFNTpcxX3Lo0/mzJpe7pVRJwN+HGahNGT0EtPDsT/nNTFDUq8e8nt0U9/8
+0eekg4MRBJEzE3A+wosIHPjzCkQgu98+nh79rPMbCpZVxNfLb136cTkubmHCWptN
+T2MbqK2L4hMcOxHGGOmI9SjFltNeKtTsVtkxh3Vj67UESPdN550centfasJYA0bj
+guRQfHWHJXYIfFwblIFkl8xtIVLTeWlQMEvc7oI8jcJOc2ri8Zdjj/55xxv/RvjC
+ZKzfjPpdkLYcN1zP/hETLD68u7WmiMAYCr8Eq9YQ3oKklUpWxRMCAAtmgjGGpm5P
+QQW+36s96Q3cuG8R0Z4Wo8y89FgWzCEzuAhemCdffoUA8kn0HJQaVndnExJb1Ebz
+wp+zsX/JqiOFvcKHJAWCaXkk0oXVi1aIV4tQyCPfhyjnd846K7g8UabAz51IJHvF
+CXRAmqJvu26NqjYOfWBJJxZQsPH4FjPfYx+e/MFPZa+UTKCfzaOHClrePHUDHw58
+Ez5ItcORYn51IWW33r+c4tlhW5mrjMD7FcjFOuYT4EIivd5BSnwLP0fjBz8TBVAY
+yyFO+YAXTQ+0MVNpZ24gT25seSAodGVzdCBrZXksIGRvIG5vdCB1c2UpIDxzb0Bl
+eGFtcGxlLm9yZz6JATcEEwEIACEFAld/jO8CGwMFCwkIBwIGFQgJCgsCBBYCAwEC
+HgECF4AACgkQ/tFT8S8Y9F3PAwgAvKav6+luvcAhrpBMO4z/Q8kDMtO5AW1KTEcz
+neqpj5eTVJVbYUgDuBlEXbFYtcZmYyYtJC5KQkN3bxPmehVUzGk27UYWMWbPIWyU
+riGcFL5BWWQaKSqiWUypzhNVnxYoiWVhHeJ36LICVMpLBaubgcpwCSW/j58yZo/7
+XRwf40OblXr4cevIW4Oq5GSxKOQF+DCErF6BeikC2i+NoqSxwNiIO/1NUxs8QfAI
+z8UT/bSUXr62BWLfeCIDGgXutMMPth3tKi4DlvLCzI6eYJrd8E3Rt7iUZm9IH8OQ
+Djv2DKnL/E/AP8oITItrOmICqfEWcj+Tk2Xep4pCCMNU+Pa0yg==
+=gG5b
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/lang/python/tests/support.py b/lang/python/tests/support.py
new file mode 100644
index 0000000..4d7135e
--- /dev/null
+++ b/lang/python/tests/support.py
@@ -0,0 +1,69 @@
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import os
+from pyme import core
+
+# known keys
+alpha = "A0FF4590BB6122EDEF6E3C542D727CC768697734"
+bob = "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2"
+encrypt_only = "F52770D5C4DB41408D918C9F920572769B9FE19C"
+sign_only = "7CCA20CCDE5394CEE71C9F0BFED153F12F18F45D"
+
+def make_filename(name):
+ return os.path.join(os.environ['top_srcdir'], 'tests', 'gpg', name)
+
+def in_srcdir(name):
+ return os.path.join(os.environ['srcdir'], name)
+
+def init_gpgme(proto):
+ core.engine_check_version(proto)
+
+verbose = int(os.environ.get('verbose', 0)) > 1
+def print_data(data):
+ if verbose:
+ try:
+ # See if it is a file-like object.
+ data.seek(0, os.SEEK_SET)
+ data = data.read()
+ except:
+ # Hope for the best.
+ pass
+ sys.stdout.buffer.write(data)
+
+def mark_key_trusted(ctx, key):
+ class Editor(object):
+ def __init__(self):
+ self.steps = ["trust", "save"]
+ def edit(self, status, args, out):
+ if args == "keyedit.prompt":
+ result = self.steps.pop(0)
+ elif args == "edit_ownertrust.value":
+ result = "5"
+ elif args == "edit_ownertrust.set_ultimate.okay":
+ result = "Y"
+ elif args == "keyedit.save.okay":
+ result = "Y"
+ else:
+ result = None
+ return result
+ with core.Data() as sink:
+ ctx.op_edit(key, Editor().edit, sink, sink)
diff --git a/lang/python/tests/t-callbacks.py b/lang/python/tests/t-callbacks.py
new file mode 100755
index 0000000..b3b4349
--- /dev/null
+++ b/lang/python/tests/t-callbacks.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+from pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+
+c = core.Context()
+c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+
+source = core.Data("Hallo Leute\n")
+sink = core.Data()
+
+# Valid passphrases, both as string and bytes.
+for passphrase in ('foo', b'foo'):
+ def passphrase_cb(hint, desc, prev_bad, hook=None):
+ assert hook == passphrase
+ return hook
+
+ c.set_passphrase_cb(passphrase_cb, passphrase)
+ c.op_encrypt([], 0, source, sink)
+
+# Returning an invalid type.
+def passphrase_cb(hint, desc, prev_bad, hook=None):
+ return 0
+
+c.set_passphrase_cb(passphrase_cb, None)
+try:
+ c.op_encrypt([], 0, source, sink)
+except Exception as e:
+ assert type(e) == TypeError
+ assert str(e) == "expected str or bytes from passphrase callback, got int"
+else:
+ assert False, "Expected an error, got none"
+
+# Raising an exception inside callback.
+myException = Exception()
+def passphrase_cb(hint, desc, prev_bad, hook=None):
+ raise myException
+
+c.set_passphrase_cb(passphrase_cb, None)
+try:
+ c.op_encrypt([], 0, source, sink)
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+# Wrong kind of callback function.
+def bad_passphrase_cb():
+ pass
+
+c.set_passphrase_cb(bad_passphrase_cb, None)
+try:
+ c.op_encrypt([], 0, source, sink)
+except Exception as e:
+ assert type(e) == TypeError
+else:
+ assert False, "Expected an error, got none"
+
+
+
+# Test the progress callback.
+parms = """<GnupgKeyParms format="internal">
+Key-Type: RSA
+Key-Length: 1024
+Name-Real: Joe Tester
+Name-Comment: with stupid passphrase
+Name-Email: joe+pyme@example.org
+Passphrase: Crypt0R0cks
+Expire-Date: 2020-12-31
+</GnupgKeyParms>
+"""
+
+messages = []
+def progress_cb(what, typ, current, total, hook=None):
+ assert hook == messages
+ messages.append(
+ "PROGRESS UPDATE: what = {}, type = {}, current = {}, total = {}"
+ .format(what, typ, current, total))
+
+c = core.Context()
+c.set_progress_cb(progress_cb, messages)
+c.op_genkey(parms, None, None)
+assert len(messages) > 0
+
+# Test exception handling.
+def progress_cb(what, typ, current, total, hook=None):
+ raise myException
+
+c = core.Context()
+c.set_progress_cb(progress_cb, None)
+try:
+ c.op_genkey(parms, None, None)
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+
+# Test the edit callback.
+c = core.Context()
+c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+c.set_passphrase_cb(lambda *args: "abc")
+sink = core.Data()
+alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)
+
+cookie = object()
+edit_cb_called = False
+def edit_cb(status, args, hook):
+ global edit_cb_called
+ edit_cb_called = True
+ assert hook == cookie
+ return "quit" if args == "keyedit.prompt" else None
+c.op_edit(alpha, edit_cb, cookie, sink)
+assert edit_cb_called
+
+# Test exceptions.
+c = core.Context()
+c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+c.set_passphrase_cb(lambda *args: "abc")
+sink = core.Data()
+
+def edit_cb(status, args):
+ raise myException
+try:
+ c.op_edit(alpha, edit_cb, None, sink)
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+
+
+# Test the status callback.
+source = core.Data("Hallo Leute\n")
+sink = core.Data()
+
+status_cb_called = False
+def status_cb(keyword, args, hook=None):
+ global status_cb_called
+ status_cb_called = True
+ assert hook == cookie
+
+c = core.Context()
+c.set_status_cb(status_cb, cookie)
+c.set_ctx_flag("full-status", "1")
+c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink)
+assert status_cb_called
+
+# Test exceptions.
+source = core.Data("Hallo Leute\n")
+sink = core.Data()
+
+def status_cb(keyword, args):
+ raise myException
+
+c = core.Context()
+c.set_status_cb(status_cb, None)
+c.set_ctx_flag("full-status", "1")
+try:
+ c.op_encrypt([alpha], constants.ENCRYPT_ALWAYS_TRUST, source, sink)
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+
+
+# Test the data callbacks.
+def read_cb(amount, hook=None):
+ assert hook == cookie
+ return 0
+def release_cb(hook=None):
+ assert hook == cookie
+data = core.Data(cbs=(read_cb, None, None, release_cb, cookie))
+try:
+ data.read()
+except Exception as e:
+ assert type(e) == TypeError
+else:
+ assert False, "Expected an error, got none"
+
+def read_cb(amount):
+ raise myException
+data = core.Data(cbs=(read_cb, None, None, lambda: None))
+try:
+ data.read()
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+
+def write_cb(what, hook=None):
+ assert hook == cookie
+ return "wrong type"
+data = core.Data(cbs=(None, write_cb, None, release_cb, cookie))
+try:
+ data.write(b'stuff')
+except Exception as e:
+ assert type(e) == TypeError
+else:
+ assert False, "Expected an error, got none"
+
+def write_cb(what):
+ raise myException
+data = core.Data(cbs=(None, write_cb, None, lambda: None))
+try:
+ data.write(b'stuff')
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
+
+
+def seek_cb(offset, whence, hook=None):
+ assert hook == cookie
+ return "wrong type"
+data = core.Data(cbs=(None, None, seek_cb, release_cb, cookie))
+try:
+ data.seek(0, os.SEEK_SET)
+except Exception as e:
+ assert type(e) == TypeError
+else:
+ assert False, "Expected an error, got none"
+
+def seek_cb(offset, whence):
+ raise myException
+data = core.Data(cbs=(None, None, seek_cb, lambda: None))
+try:
+ data.seek(0, os.SEEK_SET)
+except Exception as e:
+ assert e == myException
+else:
+ assert False, "Expected an error, got none"
diff --git a/lang/python/tests/t-data.py b/lang/python/tests/t-data.py
new file mode 100755
index 0000000..4812a2e
--- /dev/null
+++ b/lang/python/tests/t-data.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import io
+import os
+import tempfile
+from pyme import core
+
+data = core.Data('Hello world!')
+assert data.read() == b'Hello world!'
+assert data.read() == b''
+
+data.seek(0, os.SEEK_SET)
+assert data.read() == b'Hello world!'
+assert data.read() == b''
+
+data = core.Data(b'Hello world!')
+assert data.read() == b'Hello world!'
+
+data = core.Data(b'Hello world!', copy=False)
+assert data.read() == b'Hello world!'
+
+data = core.Data()
+data.write('Hello world!')
+data.seek(0, os.SEEK_SET)
+assert data.read() == b'Hello world!'
+
+data = core.Data()
+data.write(b'Hello world!')
+data.seek(0, os.SEEK_SET)
+assert data.read() == b'Hello world!'
+
+binjunk = bytes(range(256))
+data = core.Data()
+data.write(binjunk)
+data.seek(0, os.SEEK_SET)
+assert data.read() == binjunk
+
+data = core.Data()
+data.set_file_name("foobar")
+assert data.get_file_name() == "foobar"
+
+# Test reading from an existing file.
+with tempfile.NamedTemporaryFile() as tmp:
+ tmp.write(binjunk)
+ tmp.flush()
+ tmp.seek(0)
+
+ # Open using name.
+ data = core.Data(file=tmp.name)
+ assert data.read() == binjunk
+
+ # Open using name, without copying.
+ if False:
+ # delayed reads are not yet supported
+ data = core.Data(file=tmp.name, copy=False)
+ assert data.read() == binjunk
+
+ # Open using stream.
+ tmp.seek(0)
+ data = core.Data(file=tmp)
+ assert data.read() == binjunk
+
+ # Open using stream, offset, and length.
+ data = core.Data(file=tmp, offset=0, length=42)
+ assert data.read() == binjunk[:42]
+
+ # Open using name, offset, and length.
+ data = core.Data(file=tmp.name, offset=23, length=42)
+ assert data.read() == binjunk[23:23+42]
+
+# Test callbacks.
+class DataObject(object):
+ def __init__(self):
+ self.buffer = io.BytesIO()
+ self.released = False
+
+ def read(self, amount, hook=None):
+ assert not self.released
+ return self.buffer.read(amount)
+
+ def write(self, data, hook=None):
+ assert not self.released
+ return self.buffer.write(data)
+
+ def seek(self, offset, whence, hook=None):
+ assert not self.released
+ return self.buffer.seek(offset, whence)
+
+ def release(self, hook=None):
+ assert not self.released
+ self.released = True
+
+do = DataObject()
+cookie = object()
+data = core.Data(cbs=(do.read, do.write, do.seek, do.release, cookie))
+data.write('Hello world!')
+data.seek(0, os.SEEK_SET)
+assert data.read() == b'Hello world!'
+del data
+assert do.released
+
+# Again, without the cookie.
+do = DataObject()
+data = core.Data(cbs=(do.read, do.write, do.seek, do.release))
+data.write('Hello world!')
+data.seek(0, os.SEEK_SET)
+assert data.read() == b'Hello world!'
+del data
+assert do.released
diff --git a/lang/python/tests/t-decrypt-verify.py b/lang/python/tests/t-decrypt-verify.py
new file mode 100755
index 0000000..a38a965
--- /dev/null
+++ b/lang/python/tests/t-decrypt-verify.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import pyme
+from pyme import core, constants, errors
+import support
+
+def check_verify_result(result, summary, fpr, status):
+ assert len(result.signatures) == 1, "Unexpected number of signatures"
+ sig = result.signatures[0]
+ assert sig.summary == summary, "Unexpected signature summary"
+ assert sig.fpr == fpr
+ assert errors.GPGMEError(sig.status).getcode() == status
+ assert len(sig.notations) == 0
+ assert not sig.wrong_key_usage
+ assert sig.validity == constants.VALIDITY_FULL
+ assert errors.GPGMEError(sig.validity_reason).getcode() == errors.NO_ERROR
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+source = core.Data(file=support.make_filename("cipher-2.asc"))
+sink = core.Data()
+
+c.op_decrypt_verify(source, sink)
+result = c.op_decrypt_result()
+assert not result.unsupported_algorithm, \
+ "Unsupported algorithm: {}".format(result.unsupported_algorithm)
+
+support.print_data(sink)
+
+verify_result = c.op_verify_result()
+check_verify_result(verify_result,
+ constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR)
+
+# Idiomatic interface.
+with pyme.Context() as c:
+ alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)
+ bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)
+ plaintext, _, verify_result = \
+ c.decrypt(open(support.make_filename("cipher-2.asc")), verify=[alpha])
+ assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \
+ 'Plaintext not found'
+ check_verify_result(verify_result,
+ constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR)
+
+ try:
+ c.decrypt(open(support.make_filename("cipher-2.asc")),
+ verify=[alpha, bob])
+ except errors.MissingSignatures as e:
+ assert len(e.missing) == 1
+ assert e.missing[0] == bob
+ else:
+ assert False, "Expected an error, got none"
diff --git a/lang/python/tests/t-decrypt.py b/lang/python/tests/t-decrypt.py
new file mode 100755
index 0000000..2d85bc2
--- /dev/null
+++ b/lang/python/tests/t-decrypt.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import pyme
+from pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+source = core.Data(file=support.make_filename("cipher-1.asc"))
+sink = core.Data()
+
+c.op_decrypt(source, sink)
+result = c.op_decrypt_result()
+assert not result.unsupported_algorithm, \
+ "Unsupported algorithm: {}".format(result.unsupported_algorithm)
+
+support.print_data(sink)
+
+# Idiomatic interface.
+with pyme.Context() as c:
+ plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc")))
+ assert len(plaintext) > 0
+ assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \
+ 'Plaintext not found'
diff --git a/lang/python/tests/t-edit.py b/lang/python/tests/t-edit.py
new file mode 100755
index 0000000..18bcb94
--- /dev/null
+++ b/lang/python/tests/t-edit.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2005 Igor Belyi <belyi@users.sourceforge.net>
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import os
+from pyme import core, constants
+import support
+
+class KeyEditor(object):
+ def __init__(self):
+ self.steps = ["fpr", "expire", "1", "primary", "quit"]
+ self.step = 0
+ self.done = False
+ self.verbose = int(os.environ.get('verbose', 0)) > 1
+
+ def edit_fnc(self, status, args, out=None):
+ if args == "keyedit.prompt":
+ result = self.steps[self.step]
+ self.step += 1
+ elif args == "keyedit.save.okay":
+ result = "Y"
+ self.done = self.step == len(self.steps)
+ elif args == "keygen.valid":
+ result = "0"
+ else:
+ result = None
+
+ if self.verbose:
+ sys.stderr.write("Code: {}, args: {!r}, Returning: {!r}\n"
+ .format(status, args, result))
+
+ return result
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+
+c = core.Context()
+c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+c.set_passphrase_cb(lambda *args: "abc")
+c.set_armor(True)
+
+# The deprecated interface.
+editor = KeyEditor()
+c.interact(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False),
+ editor.edit_fnc)
+assert editor.done
+
+# The deprecated interface.
+sink = core.Data()
+editor = KeyEditor()
+c.op_edit(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False),
+ editor.edit_fnc, sink, sink)
+assert editor.done
diff --git a/lang/python/tests/t-encrypt-large.py b/lang/python/tests/t-encrypt-large.py
new file mode 100755
index 0000000..b9cc3b5
--- /dev/null
+++ b/lang/python/tests/t-encrypt-large.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import random
+from pyme import core, constants
+import support
+
+if len(sys.argv) == 2:
+ nbytes = int(sys.argv[1])
+else:
+ nbytes = 100000
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+ntoread = nbytes
+def read_cb(amount):
+ global ntoread
+ chunk = ntoread if ntoread < amount else amount
+ ntoread -= chunk
+ assert ntoread >= 0
+ assert chunk >= 0
+ return bytes(bytearray(random.randrange(256) for i in range(chunk)))
+
+nwritten = 0
+def write_cb(data):
+ global nwritten
+ nwritten += len(data)
+ return len(data)
+
+source = core.Data(cbs=(read_cb, None, None, lambda: None))
+sink = core.Data(cbs=(None, write_cb, None, lambda: None))
+
+keys = []
+keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False))
+keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False))
+
+c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, sink)
+result = c.op_encrypt_result()
+assert not result.invalid_recipients, \
+ "Invalid recipient encountered: {}".format(result.invalid_recipients.fpr)
+assert ntoread == 0
+
+if support.verbose:
+ sys.stderr.write(
+ "plaintext={} bytes, ciphertext={} bytes\n".format(nbytes, nwritten))
diff --git a/lang/python/tests/t-encrypt-sign.py b/lang/python/tests/t-encrypt-sign.py
new file mode 100755
index 0000000..a453f79
--- /dev/null
+++ b/lang/python/tests/t-encrypt-sign.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import pyme
+from pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+def check_result(r, typ):
+ if r.invalid_signers:
+ sys.exit("Invalid signer found: {}".format(r.invalid_signers.fpr))
+
+ if len(r.signatures) != 1:
+ sys.exit("Unexpected number of signatures created")
+
+ signature = r.signatures[0]
+ if signature.type != typ:
+ sys.exit("Wrong type of signature created")
+
+ if signature.pubkey_algo != constants.PK_DSA:
+ sys.exit("Wrong pubkey algorithm reported: {}".format(
+ signature.pubkey_algo))
+
+ if signature.hash_algo not in (constants.MD_SHA1, constants.MD_RMD160):
+ sys.exit("Wrong hash algorithm reported: {}".format(
+ signature.hash_algo))
+
+ if signature.sig_class != 0:
+ sys.exit("Wrong signature class reported: {}".format(
+ signature.sig_class))
+
+ if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734":
+ sys.exit("Wrong fingerprint reported: {}".format(signature.fpr))
+
+keys = []
+keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False))
+keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False))
+
+for recipients in (keys, []):
+ source = core.Data("Hallo Leute\n")
+ sink = core.Data()
+
+ c.op_encrypt_sign(recipients, constants.ENCRYPT_ALWAYS_TRUST, source, sink)
+ result = c.op_encrypt_result()
+ assert not result.invalid_recipients, \
+ "Invalid recipient encountered: {}".format(
+ result.invalid_recipients.fpr)
+
+ result = c.op_sign_result()
+ check_result(result, constants.SIG_MODE_NORMAL)
+
+ support.print_data(sink)
+
+
+# Idiomatic interface.
+with pyme.Context(armor=True) as c:
+ message = "Hallo Leute\n".encode()
+ ciphertext, _, sig_result = c.encrypt(message,
+ recipients=keys,
+ always_trust=True)
+ assert len(ciphertext) > 0
+ assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found'
+ check_result(sig_result, constants.SIG_MODE_NORMAL)
+
+ c.signers = [c.get_key(support.sign_only, True)]
+ c.encrypt(message, recipients=keys, always_trust=True)
+
+ c.signers = [c.get_key(support.encrypt_only, True)]
+ try:
+ c.encrypt(message, recipients=keys, always_trust=True)
+ except pyme.errors.InvalidSigners as e:
+ assert len(e.signers) == 1
+ assert support.encrypt_only.endswith(e.signers[0].fpr)
+ else:
+ assert False, "Expected an InvalidSigners error, got none"
diff --git a/lang/python/tests/t-encrypt-sym.py b/lang/python/tests/t-encrypt-sym.py
new file mode 100755
index 0000000..d577184
--- /dev/null
+++ b/lang/python/tests/t-encrypt-sym.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+import pyme
+from pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+
+for passphrase in ("abc", b"abc"):
+ c = core.Context()
+ c.set_armor(True)
+ c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+
+ source = core.Data("Hallo Leute\n")
+ cipher = core.Data()
+
+ passphrase_cb_called = 0
+ def passphrase_cb(hint, desc, prev_bad, hook=None):
+ global passphrase_cb_called
+ passphrase_cb_called += 1
+ return passphrase
+
+ c.set_passphrase_cb(passphrase_cb, None)
+
+ c.op_encrypt([], 0, source, cipher)
+ assert passphrase_cb_called == 1, \
+ "Callback called {} times".format(passphrase_cb_called)
+ support.print_data(cipher)
+
+ c = core.Context()
+ c.set_armor(True)
+ c.set_pinentry_mode(constants.PINENTRY_MODE_LOOPBACK)
+ c.set_passphrase_cb(passphrase_cb, None)
+ plain = core.Data()
+ cipher.seek(0, os.SEEK_SET)
+
+ c.op_decrypt(cipher, plain)
+ # Seems like the passphrase is cached.
+ #assert passphrase_cb_called == 2, \
+ # "Callback called {} times".format(passphrase_cb_called)
+ support.print_data(plain)
+
+ plain.seek(0, os.SEEK_SET)
+ plaintext = plain.read()
+ assert plaintext == b"Hallo Leute\n", \
+ "Wrong plaintext {!r}".format(plaintext)
+
+# Idiomatic interface.
+for passphrase in ("abc", b"abc"):
+ with pyme.Context(armor=True) as c:
+ # Check that the passphrase callback is not altered.
+ def f(*args):
+ assert False
+ c.set_passphrase_cb(f)
+
+ message = "Hallo Leute\n".encode()
+ ciphertext, _, _ = c.encrypt(message,
+ passphrase=passphrase,
+ sign=False)
+ assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found'
+
+ plaintext, _, _ = c.decrypt(ciphertext, passphrase=passphrase)
+ assert plaintext == message, 'Message body not recovered'
+
+ assert c._passphrase_cb[1] == f, "Passphrase callback not restored"
diff --git a/lang/python/tests/t-encrypt.py b/lang/python/tests/t-encrypt.py
new file mode 100755
index 0000000..65e7d24
--- /dev/null
+++ b/lang/python/tests/t-encrypt.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import pyme
+from pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+source = core.Data("Hallo Leute\n")
+sink = core.Data()
+
+keys = []
+keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False))
+keys.append(c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False))
+
+c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, sink)
+result = c.op_encrypt_result()
+assert not result.invalid_recipients, \
+ "Invalid recipients: {}".format(", ".join(r.fpr for r in result.recipients))
+support.print_data(sink)
+
+# Idiomatic interface.
+with pyme.Context(armor=True) as c:
+ ciphertext, _, _ = c.encrypt("Hallo Leute\n".encode(),
+ recipients=keys,
+ sign=False,
+ always_trust=True)
+ assert len(ciphertext) > 0
+ assert ciphertext.find(b'BEGIN PGP MESSAGE') > 0, 'Marker not found'
+
+ c.encrypt("Hallo Leute\n".encode(),
+ recipients=[c.get_key(support.encrypt_only, False)],
+ sign=False, always_trust=True)
+
+ try:
+ c.encrypt("Hallo Leute\n".encode(),
+ recipients=[c.get_key(support.sign_only, False)],
+ sign=False, always_trust=True)
+ except pyme.errors.InvalidRecipients as e:
+ assert len(e.recipients) == 1
+ assert support.sign_only.endswith(e.recipients[0].fpr)
+ else:
+ assert False, "Expected an InvalidRecipients error, got none"
diff --git a/lang/python/tests/t-export.py b/lang/python/tests/t-export.py
new file mode 100755
index 0000000..db36b98
--- /dev/null
+++ b/lang/python/tests/t-export.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+sink = core.Data()
+c.op_export_ext(['Alpha', 'Bob'], 0, sink)
+support.print_data(sink)
+
+# Again. Now using a key array.
+keys = []
+keys.append(c.get_key("0x68697734", False)) # Alpha
+keys.append(c.get_key("0xA9E3B0B2", False)) # Bob
+sink = core.Data()
+c.op_export_keys(keys, 0, sink)
+support.print_data(sink)
diff --git a/lang/python/tests/t-file-name.py b/lang/python/tests/t-file-name.py
new file mode 100755
index 0000000..e93b120
--- /dev/null
+++ b/lang/python/tests/t-file-name.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+from pyme import core, constants
+import support
+
+testname = "abcde12345"
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+source = core.Data("Hallo Leute\n")
+source.set_file_name(testname)
+cipher = core.Data()
+plain = core.Data()
+
+keys = []
+keys.append(c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False))
+
+c.op_encrypt(keys, constants.ENCRYPT_ALWAYS_TRUST, source, cipher)
+cipher.seek(0, os.SEEK_SET)
+c.op_decrypt(cipher, plain)
+result = c.op_decrypt_result()
+assert result.file_name == testname
diff --git a/lang/python/tests/t-idiomatic.py b/lang/python/tests/t-idiomatic.py
new file mode 100755
index 0000000..f063206
--- /dev/null
+++ b/lang/python/tests/t-idiomatic.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import io
+import os
+import tempfile
+import pyme
+import support
+
+support.init_gpgme(pyme.constants.PROTOCOL_OpenPGP)
+
+# Both Context and Data can be used as context manager:
+with pyme.Context() as c, pyme.Data() as d:
+ c.get_engine_info()
+ d.write(b"Halloechen")
+ leak_c = c
+ leak_d = d
+assert leak_c.wrapped == None
+assert leak_d.wrapped == None
+
+def sign_and_verify(source, signed, sink):
+ with pyme.Context() as c:
+ c.op_sign(source, signed, pyme.constants.SIG_MODE_NORMAL)
+ signed.seek(0, os.SEEK_SET)
+ c.op_verify(signed, None, sink)
+ result = c.op_verify_result()
+
+ assert len(result.signatures) == 1, "Unexpected number of signatures"
+ sig = result.signatures[0]
+ assert sig.summary == (pyme.constants.SIGSUM_VALID |
+ pyme.constants.SIGSUM_GREEN)
+ assert pyme.errors.GPGMEError(sig.status).getcode() == pyme.errors.NO_ERROR
+
+ sink.seek(0, os.SEEK_SET)
+ assert sink.read() == b"Hallo Leute\n"
+
+# Demonstrate automatic wrapping of file-like objects with 'fileno'
+# method.
+with tempfile.TemporaryFile() as source, \
+ tempfile.TemporaryFile() as signed, \
+ tempfile.TemporaryFile() as sink:
+ source.write(b"Hallo Leute\n")
+ source.seek(0, os.SEEK_SET)
+
+ sign_and_verify(source, signed, sink)
+
+if sys.version_info[0] == 3:
+ # Python2's io.BytesIO does not implement the buffer interface,
+ # hence we cannot use it as sink.
+
+ # XXX: Python's io.BytesIo.truncate does not work as advertised.
+ # http://bugs.python.org/issue27261
+ bio = io.BytesIO()
+ bio.truncate(1)
+ if len(bio.getvalue()) != 1:
+ # This version of Python is affected, preallocate buffer.
+ preallocate = 128*b'\x00'
+ else:
+ preallocate = b''
+
+ # Demonstrate automatic wrapping of objects implementing the buffer
+ # interface, and the use of data objects with the 'with' statement.
+ with io.BytesIO(preallocate) as signed, pyme.Data() as sink:
+ sign_and_verify(b"Hallo Leute\n", signed, sink)
diff --git a/lang/python/tests/t-import.py b/lang/python/tests/t-import.py
new file mode 100755
index 0000000..0b50d02
--- /dev/null
+++ b/lang/python/tests/t-import.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 pyme import core, constants
+import support
+
+def check_result(result, fpr, secret):
+ assert result.considered == 1 or (secret and result.considered == 3)
+ assert result.no_user_id == 0
+ assert not ((secret and result.imported != 0)
+ or (not secret and (result.imported != 0
+ and result.imported != 1)))
+ assert result.imported_rsa == 0
+ assert not ((secret and (result.unchanged != 0 and result.unchanged != 1))
+ or (not secret and ((result.imported == 0
+ and result.unchanged != 1)
+ or (result.imported == 1
+ and result.unchanged != 0))))
+ assert result.new_user_ids == 0
+ assert result.new_sub_keys == 0
+ assert not ((secret
+ and ((result.secret_imported == 0
+ and result.new_signatures != 0)
+ or (result.secret_imported == 1
+ and result.new_signatures > 1)))
+ or (not secret and result.new_signatures != 0))
+ assert result.new_revocations == 0
+ assert not ((secret and result.secret_read != 1 and result.secret_read != 3)
+ or (not secret and result.secret_read != 0))
+ assert not ((secret and result.secret_imported != 0
+ and result.secret_imported != 1
+ and result.secret_imported != 2)
+ or (not secret and result.secret_imported != 0))
+ assert not ((secret
+ and ((result.secret_imported == 0
+ and result.secret_unchanged != 1
+ and result.secret_unchanged != 2)
+ or (result.secret_imported == 1
+ and result.secret_unchanged != 0)))
+ or (not secret and result.secret_unchanged != 0))
+ assert result.not_imported == 0
+ if secret:
+ assert not (len(result.imports) in (0, 3))
+ else:
+ assert not (len(result.imports) in (0, 2))
+
+ assert fpr == result.imports[0].fpr
+ assert len(result.imports) == 1 or fpr == result.imports[1].fpr
+ assert result.imports[0].result == 0
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+c.op_import(core.Data(file=support.make_filename("pubkey-1.asc")))
+result = c.op_import_result()
+check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", False)
+
+c.op_import(core.Data(file=support.make_filename("seckey-1.asc")))
+result = c.op_import_result()
+check_result(result, "ADAB7FCC1F4DE2616ECFA402AF82244F9CD9FD55", True)
diff --git a/lang/python/tests/t-keylist.py b/lang/python/tests/t-keylist.py
new file mode 100755
index 0000000..5e8b333
--- /dev/null
+++ b/lang/python/tests/t-keylist.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+# Check expration of keys. This test assumes three subkeys of which
+# 2 are expired; it is used with the "Whisky" test key. It has
+# already been checked that these 3 subkeys are available.
+def check_whisky(name, key):
+ sub1 = key.subkeys[2]
+ sub2 = key.subkeys[3]
+
+ assert sub1.expired and sub2.expired, \
+ "Subkey of `{}' not flagged as expired".format(name)
+ assert sub1.expires == 1129636886 and sub2.expires == 1129636939, \
+ "Subkey of `{}' has wrong expiration date".format(name)
+
+keys = [
+ [ "A0FF4590BB6122EDEF6E3C542D727CC768697734", "6AE6D7EE46A871F8",
+ [ [ "Alfa Test", "demo key", "alfa@example.net" ],
+ [ "Alpha Test", "demo key", "alpha@example.net" ],
+ [ "Alice", "demo key", "" ] ], 1 ],
+ [ "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", "5381EA4EE29BA37F",
+ [ [ "Bob", "demo key", "" ],
+ [ "Bravo Test", "demo key", "bravo@example.net" ] ], 1 ],
+ [ "61EE841A2A27EB983B3B3C26413F4AF31AFDAB6C", "E71E72ACBC43DA60",
+ [ [ "Charlie Test", "demo key", "charlie@example.net" ] ], 1 ],
+ [ "6560C59C43D031C54D7C588EEBA9F240EB9DC9E6", "06F22880B0C45424",
+ [ [ "Delta Test", "demo key", "delta@example.net" ] ], 1 ],
+ [ "3531152DE293E26A07F504BC318C1FAEFAEF6D1B", "B5C79E1A7272144D",
+ [ [ "Echelon", "demo key", "" ],
+ [ "Echo Test", "demo key", "echo@example.net" ],
+ [ "Eve", "demo key", "" ] ], 1 ],
+ [ "56D33268F7FE693FBB594762D4BF57F37372E243", "0A32EE79EE45198E",
+ [ [ "Foxtrot Test", "demo key", "foxtrot@example.net" ] ], 1 ],
+ [ "C9C07DCC6621B9FB8D071B1D168410A48FC282E6", "247491CC9DCAD354",
+ [ [ "Golf Test", "demo key", "golf@example.net" ] ], 1 ],
+ [ "9E91CBB11E4D4135583EF90513DB965534C6E3F1", "76E26537D622AD0A",
+ [ [ "Hotel Test", "demo key", "hotel@example.net" ] ], 1 ],
+ [ "CD538D6CC9FB3D745ECDA5201FE8FC6F04259677", "C1C8EFDE61F76C73",
+ [ [ "India Test", "demo key", "india@example.net" ] ], 1 ],
+ [ "F8F1EDC73995AB739AD54B380C820C71D2699313", "BD0B108735F8F136",
+ [ [ "Juliet Test", "demo key", "juliet@example.net" ] ], 1 ],
+ [ "3FD11083779196C2ECDD9594AD1B0FAD43C2D0C7", "86CBB34A9AF64D02",
+ [ [ "Kilo Test", "demo key", "kilo@example.net" ] ], 1 ],
+ [ "1DDD28CEF714F5B03B8C246937CAB51FB79103F8", "0363B449FE56350C",
+ [ [ "Lima Test", "demo key", "lima@example.net" ] ], 1 ],
+ [ "2686AA191A278013992C72EBBE794852BE5CF886", "5F600A834F31EAE8",
+ [ [ "Mallory", "demo key", "" ],
+ [ "Mike Test", "demo key", "mike@example.net" ] ], 1 ],
+ [ "5AB9D6D7BAA1C95B3BAA3D9425B00FD430CEC684", "4C1D63308B70E472",
+ [ [ "November Test", "demo key", "november@example.net" ] ], 1 ],
+ [ "43929E89F8F79381678CAE515F6356BA6D9732AC", "FF0785712681619F",
+ [ [ "Oscar Test", "demo key", "oscar@example.net" ] ], 1 ],
+ [ "6FAA9C201E5E26DCBAEC39FD5D15E01D3FF13206", "2764E18263330D9C",
+ [ [ "Papa test", "demo key", "papa@example.net" ] ], 1 ],
+ [ "A7969DA1C3297AA96D49843F1C67EC133C661C84", "6CDCFC44A029ACF4",
+ [ [ "Quebec Test", "demo key", "quebec@example.net" ] ], 1 ],
+ [ "38FBE1E4BF6A5E1242C8F6A13BDBEDB1777FBED3", "9FAB805A11D102EA",
+ [ [ "Romeo Test", "demo key", "romeo@example.net" ] ], 1 ],
+ [ "045B2334ADD69FC221076841A5E67F7FA3AE3EA1", "93B88B0F0F1B50B4",
+ [ [ "Sierra Test", "demo key", "sierra@example.net" ] ], 1 ],
+ [ "ECAC774F4EEEB0620767044A58CB9A4C85A81F38", "97B60E01101C0402",
+ [ [ "Tango Test", "demo key", "tango@example.net" ] ], 1 ],
+ [ "0DBCAD3F08843B9557C6C4D4A94C0F75653244D6", "93079B915522BDB9",
+ [ [ "Uniform Test", "demo key", "uniform@example.net" ] ], 1 ],
+ [ "E8143C489C8D41124DC40D0B47AF4B6961F04784", "04071FB807287134",
+ [ [ "Victor Test", "demo key", "victor@example.org" ] ], 1 ],
+ [ "E8D6C90B683B0982BD557A99DEF0F7B8EC67DBDE", "D7FBB421FD6E27F6",
+ [ [ "Whisky Test", "demo key", "whisky@example.net" ] ], 3,
+ check_whisky ],
+ [ "04C1DF62EFA0EBB00519B06A8979A6C5567FB34A", "5CC6F87F41E408BE",
+ [ [ "XRay Test", "demo key", "xray@example.net" ] ], 1 ],
+ [ "ED9B316F78644A58D042655A9EEF34CD4B11B25F", "5ADFD255F7B080AD",
+ [ [ "Yankee Test", "demo key", "yankee@example.net" ] ], 1 ],
+ [ "23FD347A419429BACCD5E72D6BC4778054ACD246", "EF9DC276A172C881",
+ [ [ "Zulu Test", "demo key", "zulu@example.net" ] ], 1 ],
+]
+
+def check_global(key, uids, n_subkeys):
+ assert not key.revoked, "Key unexpectedly revoked"
+ assert not key.expired, "Key unexpectedly expired"
+ assert not key.disabled, "Key unexpectedly disabled"
+ assert not key.invalid, "Key unexpectedly invalid"
+ assert key.can_sign, "Key unexpectedly unusable for signing"
+ assert key.can_certify, "Key unexpectedly unusable for certifications"
+ assert not key.secret, "Key unexpectedly secret"
+ assert not key.protocol != constants.PROTOCOL_OpenPGP, \
+ "Key has unexpected protocol: {}".format(key.protocol)
+ assert not key.issuer_serial, \
+ "Key unexpectedly carries issuer serial: {}".format(key.issuer_serial)
+ assert not key.issuer_name, \
+ "Key unexpectedly carries issuer name: {}".format(key.issuer_name)
+ assert not key.chain_id, \
+ "Key unexpectedly carries chain ID: {}".format(key.chain_id)
+
+ # Only key Alfa is trusted
+ assert key.uids[0].name == 'Alfa Test' \
+ or key.owner_trust == constants.VALIDITY_UNKNOWN, \
+ "Key has unexpected owner trust: {}".format(key.owner_trust)
+ assert key.uids[0].name != 'Alfa Test' \
+ or key.owner_trust == constants.VALIDITY_ULTIMATE, \
+ "Key has unexpected owner trust: {}".format(key.owner_trust)
+
+ assert len(key.subkeys) - 1 == n_subkeys, \
+ "Key `{}' has unexpected number of subkeys".format(uids[0][0])
+
+
+def check_subkey(fpr, which, subkey):
+ assert not subkey.revoked, which + " key unexpectedly revoked"
+ assert not subkey.expired, which + " key unexpectedly expired"
+ assert not subkey.disabled, which + " key unexpectedly disabled"
+ assert not subkey.invalid, which + " key unexpectedly invalid"
+
+ if which == "Primary":
+ assert not subkey.can_encrypt, \
+ which + " key unexpectedly usable for encryption"
+ assert subkey.can_sign, \
+ which + " key unexpectedly unusable for signing"
+ assert subkey.can_certify, \
+ which + " key unexpectedly unusable for certifications"
+ else:
+ assert subkey.can_encrypt, \
+ which + " key unexpectedly unusable for encryption"
+ assert not subkey.can_sign, \
+ which + " key unexpectedly usable for signing"
+ assert not subkey.can_certify, \
+ which + " key unexpectedly usable for certifications"
+
+ assert not subkey.secret, which + " key unexpectedly secret"
+ assert not subkey.is_cardkey, "Public key marked as card key"
+ assert not subkey.card_number, "Public key with card number set"
+ assert not subkey.pubkey_algo != (constants.PK_DSA if which == "Primary"
+ else constants.PK_ELG_E), \
+ which + " key has unexpected public key algo: {}".\
+ format(subkey.pubkey_algo)
+ assert subkey.length == 1024, \
+ which + " key has unexpected length: {}".format(subkey.length)
+ assert fpr.endswith(subkey.keyid), \
+ which + " key has unexpected key ID: {}".format(subkey.keyid)
+ assert which == "Secondary" or subkey.fpr == fpr, \
+ which + " key has unexpected fingerprint: {}".format(subkey.fpr)
+ assert not subkey.expires, \
+ which + " key unexpectedly expires: {}".format(subkey.expires)
+
+def check_uid(which, ref, uid):
+ assert not uid.revoked, which + " user ID unexpectedly revoked"
+ assert not uid.invalid, which + " user ID unexpectedly invalid"
+ assert uid.validity == (constants.VALIDITY_UNKNOWN
+ if uid.name.split()[0]
+ not in {'Alfa', 'Alpha', 'Alice'} else
+ constants.VALIDITY_ULTIMATE), \
+ which + " user ID has unexpectedly validity: {}".format(uid.validity)
+ assert not uid.signatures, which + " user ID unexpectedly signed"
+ assert uid.name == ref[0], \
+ "Unexpected name in {} user ID: {!r}".format(which.lower(), uid.name)
+ assert uid.comment == ref[1], \
+ "Unexpected comment in {} user ID: {!r}".format(which.lower(),
+ uid.comment)
+ assert uid.email == ref[2], \
+ "Unexpected email in {} user ID: {!r}".format(which.lower(), uid.email)
+
+i = 0
+c.op_keylist_start(None, False)
+key = c.op_keylist_next ()
+while key:
+ try:
+ if len(keys[i]) == 4:
+ fpr, sec_keyid, uids, n_subkeys = keys[i]
+ misc_check = None
+ else:
+ fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i]
+ except IndexError:
+ # There are more keys. We don't check for that.
+ break
+
+ # Global key flags.
+ check_global(key, uids, n_subkeys)
+ check_subkey(fpr, "Primary", key.subkeys[0])
+ check_subkey(sec_keyid, "Secondary", key.subkeys[1])
+
+ assert len(key.uids) == len(uids)
+ check_uid("First", uids[0], key.uids[0])
+ if len(key.uids) > 1:
+ check_uid("Second", uids[1], key.uids[1])
+ if len(key.uids) > 2:
+ check_uid("Third", uids[2], key.uids[2])
+
+ if misc_check:
+ misc_check (uids[0][0], key)
+ key = c.op_keylist_next ()
+ i += 1
+
+c.op_keylist_end()
+result = c.op_keylist_result()
+assert not result.truncated, "Key listing unexpectedly truncated"
+
+
+for i, key in enumerate(c.keylist()):
+ try:
+ if len(keys[i]) == 4:
+ fpr, sec_keyid, uids, n_subkeys = keys[i]
+ misc_check = None
+ else:
+ fpr, sec_keyid, uids, n_subkeys, misc_check = keys[i]
+ except IndexError:
+ # There are more keys. We don't check for that.
+ break
+
+ # Global key flags.
+ check_global(key, uids, n_subkeys)
+ check_subkey(fpr, "Primary", key.subkeys[0])
+ check_subkey(sec_keyid, "Secondary", key.subkeys[1])
+
+ assert len(key.uids) == len(uids)
+ check_uid("First", uids[0], key.uids[0])
+ if len(key.uids) > 1:
+ check_uid("Second", uids[1], key.uids[1])
+ if len(key.uids) > 2:
+ check_uid("Third", uids[2], key.uids[2])
+
+ if misc_check:
+ misc_check (uids[0][0], key)
diff --git a/lang/python/tests/t-protocol-assuan.py b/lang/python/tests/t-protocol-assuan.py
new file mode 100755
index 0000000..172c7d0
--- /dev/null
+++ b/lang/python/tests/t-protocol-assuan.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import pyme
+
+with pyme.Context(protocol=pyme.constants.PROTOCOL_ASSUAN) as c:
+ # Do nothing.
+ c.assuan_transact('nop')
+ c.assuan_transact('NOP')
+ c.assuan_transact(['NOP'])
+
+ err = c.assuan_transact('idontexist')
+ assert err.getsource() == pyme.errors.SOURCE_GPGAGENT
+ assert err.getcode() == pyme.errors.ASS_UNKNOWN_CMD
+
+ # Invoke the pinentry to get a confirmation.
+ c.assuan_transact(['GET_CONFIRMATION', 'Hello there'])
+
+ data = []
+ def data_cb(line):
+ data.append(line)
+
+ err = c.assuan_transact(['GETINFO', 'version'], data_cb=data_cb)
+ assert not err
+ assert len(data) == 1
+
+ data = []
+ err = c.assuan_transact(['GETINFO', 's2k_count'], data_cb=data_cb)
+ if not err:
+ assert len(data) == 1
+ assert int(data[0]) > 0
+
+ # XXX HELP sends status lines if we could use ASSUAN_CONVEY_COMMENTS.
+
+ status = []
+ def status_cb(line, args):
+ status.append((line, args))
+
+ alphas_grip = '76F7E2B35832976B50A27A282D9B87E44577EB66'
+ err = c.assuan_transact(['KEYINFO', alphas_grip], status_cb=status_cb)
+ if not err:
+ assert len(status) == 1
+ line, args = status[0]
+ assert line.startswith('KEYINFO')
+ assert args.startswith(alphas_grip)
+
+ # XXX: test these callbacks, e.g. using PRESET_PASSPHRASE
+ # XXX: once issue2428 is resolved
+ def inq_cb(name, args):
+ print("inq_cb", name, args)
diff --git a/lang/python/tests/t-sig-notation.py b/lang/python/tests/t-sig-notation.py
new file mode 100755
index 0000000..777bc0b
--- /dev/null
+++ b/lang/python/tests/t-sig-notation.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+from pyme import core, constants
+import support
+
+expected_notations = {
+ "laughing@me": ("Just Squeeze Me", constants.SIG_NOTATION_HUMAN_READABLE),
+ "preferred-email-encoding@pgp.com": ("pgpmime",
+ constants.SIG_NOTATION_HUMAN_READABLE
+ | constants.SIG_NOTATION_CRITICAL),
+ None: ("http://www.gnu.org/policy/", 0),
+}
+
+# GnuPG prior to 2.1.13 did not report the critical flag correctly.
+with core.Context() as c:
+ version = c.engine_info.version
+ have_correct_sig_data = not (version.startswith("1.")
+ or version == "2.1.1"
+ or (version.startswith("2.1.1")
+ and version[5] < '3'))
+
+def check_result(result):
+ assert len(result.signatures) == 1, "Unexpected number of signatures"
+ sig = result.signatures[0]
+ assert len(sig.notations) == len(expected_notations)
+
+ for r in sig.notations:
+ assert not 'name_len' in dir(r)
+ assert not 'value_len' in dir(r)
+ assert r.name in expected_notations
+ value, flags = expected_notations.pop(r.name)
+
+ assert r.value == value, \
+ "Expected {!r}, got {!r}".format(value, r.value)
+ assert r.human_readable \
+ == bool(flags&constants.SIG_NOTATION_HUMAN_READABLE)
+ assert r.critical \
+ == (bool(flags&constants.SIG_NOTATION_CRITICAL)
+ if have_correct_sig_data else False)
+
+ assert len(expected_notations) == 0
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+
+source = core.Data("Hallo Leute\n")
+signed = core.Data()
+
+c = core.Context()
+for name, (value, flags) in expected_notations.items():
+ c.sig_notation_add(name, value, flags)
+
+c.op_sign(source, signed, constants.SIG_MODE_NORMAL)
+
+signed.seek(0, os.SEEK_SET)
+sink = core.Data()
+c.op_verify(signed, None, sink)
+result = c.op_verify_result()
+check_result(result)
diff --git a/lang/python/tests/t-sign.py b/lang/python/tests/t-sign.py
new file mode 100755
index 0000000..b0e211a
--- /dev/null
+++ b/lang/python/tests/t-sign.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import os
+import pyme
+from pyme import core, constants
+import support
+
+def fail(msg):
+ raise RuntimeError(msg)
+
+def check_result(r, typ):
+ if r.invalid_signers:
+ fail("Invalid signer found: {}".format(r.invalid_signers.fpr))
+
+ if len(r.signatures) != 1:
+ fail("Unexpected number of signatures created")
+
+ signature = r.signatures[0]
+ if signature.type != typ:
+ fail("Wrong type of signature created")
+
+ if signature.pubkey_algo != constants.PK_DSA:
+ fail("Wrong pubkey algorithm reported: {}".format(
+ signature.pubkey_algo))
+
+ if signature.hash_algo != constants.MD_SHA1:
+ fail("Wrong hash algorithm reported: {}".format(
+ signature.hash_algo))
+
+ if signature.sig_class != 1:
+ fail("Wrong signature class reported: {}".format(
+ signature.sig_class))
+
+ if signature.fpr != "A0FF4590BB6122EDEF6E3C542D727CC768697734":
+ fail("Wrong fingerprint reported: {}".format(signature.fpr))
+
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_textmode(True)
+c.set_armor(True)
+
+source = core.Data("Hallo Leute\n")
+sink = core.Data()
+
+c.op_sign(source, sink, constants.SIG_MODE_NORMAL)
+
+result = c.op_sign_result()
+check_result(result, constants.SIG_MODE_NORMAL)
+support.print_data(sink)
+
+# Now a detached signature.
+source.seek(0, os.SEEK_SET)
+sink = core.Data()
+
+c.op_sign(source, sink, constants.SIG_MODE_DETACH)
+
+result = c.op_sign_result()
+check_result(result, constants.SIG_MODE_DETACH)
+support.print_data(sink)
+
+# And finally a cleartext signature. */
+source.seek(0, os.SEEK_SET)
+sink = core.Data()
+
+c.op_sign(source, sink, constants.SIG_MODE_CLEAR)
+
+result = c.op_sign_result()
+check_result(result, constants.SIG_MODE_CLEAR)
+support.print_data(sink)
+
+# Idiomatic interface.
+with pyme.Context(armor=True, textmode=True) as c:
+ message = "Hallo Leute\n".encode()
+ signed, _ = c.sign(message)
+ assert len(signed) > 0
+ assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found'
+
+ signed, _ = c.sign(message, mode=pyme.constants.SIG_MODE_DETACH)
+ assert len(signed) > 0
+ assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found'
+
+ signed, _ = c.sign(message, mode=pyme.constants.SIG_MODE_CLEAR)
+ assert len(signed) > 0
+ assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found'
+ assert signed.find(message) > 0, 'Message content not found'
+ assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found'
+
+with pyme.Context() as c:
+ message = "Hallo Leute\n".encode()
+
+ c.signers = [c.get_key(support.sign_only, True)]
+ c.sign(message)
+
+ c.signers = [c.get_key(support.encrypt_only, True)]
+ try:
+ c.sign(message)
+ except pyme.errors.InvalidSigners as e:
+ assert len(e.signers) == 1
+ assert support.encrypt_only.endswith(e.signers[0].fpr)
+ else:
+ assert False, "Expected an InvalidSigners error, got none"
diff --git a/lang/python/tests/t-signers.py b/lang/python/tests/t-signers.py
new file mode 100755
index 0000000..11403af
--- /dev/null
+++ b/lang/python/tests/t-signers.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import pyme
+from pyme import core, constants
+import support
+
+def fail(msg):
+ raise RuntimeError(msg)
+
+def check_result(r, typ):
+ if r.invalid_signers:
+ fail("Invalid signer found: {}".format(r.invalid_signers.fpr))
+
+ if len(r.signatures) != 2:
+ fail("Unexpected number of signatures created")
+
+ for signature in r.signatures:
+ if signature.type != typ:
+ fail("Wrong type of signature created")
+
+ if signature.pubkey_algo != constants.PK_DSA:
+ fail("Wrong pubkey algorithm reported: {}".format(
+ signature.pubkey_algo))
+
+ if signature.hash_algo != constants.MD_SHA1:
+ fail("Wrong hash algorithm reported: {}".format(
+ signature.hash_algo))
+
+ if signature.sig_class != 1:
+ fail("Wrong signature class reported: got {}, want {}".format(
+ signature.sig_class, 1))
+
+ if signature.fpr not in ("A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ "23FD347A419429BACCD5E72D6BC4778054ACD246"):
+ fail("Wrong fingerprint reported: {}".format(signature.fpr))
+
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_textmode(True)
+c.set_armor(True)
+
+keys = []
+c.op_keylist_start('', True)
+keys.append(c.op_keylist_next())
+keys.append(c.op_keylist_next())
+c.op_keylist_end()
+
+c.signers_add(keys[0])
+c.signers_add(keys[1])
+
+for mode in (constants.SIG_MODE_NORMAL, constants.SIG_MODE_DETACH,
+ constants.SIG_MODE_CLEAR):
+ source = core.Data("Hallo Leute\n")
+ sink = core.Data()
+
+ c.op_sign(source, sink, mode)
+
+ result = c.op_sign_result()
+ check_result(result, mode)
+ support.print_data(sink)
+
+# Idiomatic interface.
+with pyme.Context(armor=True, textmode=True, signers=keys) as c:
+ message = "Hallo Leute\n".encode()
+ signed, result = c.sign(message)
+ check_result(result, constants.SIG_MODE_NORMAL)
+ assert signed.find(b'BEGIN PGP MESSAGE') > 0, 'Message not found'
+
+ signed, result = c.sign(message, mode=constants.SIG_MODE_DETACH)
+ check_result(result, constants.SIG_MODE_DETACH)
+ assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found'
+
+ signed, result = c.sign(message, mode=constants.SIG_MODE_CLEAR)
+ check_result(result, constants.SIG_MODE_CLEAR)
+ assert signed.find(b'BEGIN PGP SIGNED MESSAGE') > 0, 'Message not found'
+ assert signed.find(message) > 0, 'Message content not found'
+ assert signed.find(b'BEGIN PGP SIGNATURE') > 0, 'Signature not found'
diff --git a/lang/python/tests/t-trustlist.py b/lang/python/tests/t-trustlist.py
new file mode 100755
index 0000000..4253bd7
--- /dev/null
+++ b/lang/python/tests/t-trustlist.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 pyme import core, constants
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+
+def dump_item(item):
+ print("l={} k={} t={} o={} v={} u={}".format(
+ item.level, item.keyid, item.type, item.owner_trust,
+ item.validity, item.name))
+
+c.op_trustlist_start("alice", 0)
+while True:
+ item = c.op_trustlist_next()
+ if not item:
+ break
+ dump_item(item)
+c.op_trustlist_end()
+
+for item in c.op_trustlist_all("alice", 0):
+ dump_item(item)
diff --git a/lang/python/tests/t-verify.py b/lang/python/tests/t-verify.py
new file mode 100755
index 0000000..39f6176
--- /dev/null
+++ b/lang/python/tests/t-verify.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import sys
+import os
+import pyme
+from pyme import core, constants, errors
+import support
+
+test_text1 = b"Just GNU it!\n"
+test_text1f= b"Just GNU it?\n"
+test_sig1 = b"""-----BEGIN PGP SIGNATURE-----
+
+iN0EABECAJ0FAjoS+i9FFIAAAAAAAwA5YmFyw7bDpMO8w58gZGFzIHdhcmVuIFVt
+bGF1dGUgdW5kIGpldHp0IGVpbiBwcm96ZW50JS1aZWljaGVuNRSAAAAAAAgAJGZv
+b2Jhci4xdGhpcyBpcyBhIG5vdGF0aW9uIGRhdGEgd2l0aCAyIGxpbmVzGhpodHRw
+Oi8vd3d3Lmd1Lm9yZy9wb2xpY3kvAAoJEC1yfMdoaXc0JBIAoIiLlUsvpMDOyGEc
+dADGKXF/Hcb+AKCJWPphZCphduxSvrzH0hgzHdeQaA==
+=nts1
+-----END PGP SIGNATURE-----
+"""
+
+test_sig2 = b"""-----BEGIN PGP MESSAGE-----
+
+owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH
+GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf
+y1kvP4y+8D5a11ang0udywsA
+=Crq6
+-----END PGP MESSAGE-----
+"""
+
+# A message with a prepended but unsigned plaintext packet.
+double_plaintext_sig = b"""-----BEGIN PGP MESSAGE-----
+
+rDRiCmZvb2Jhci50eHRF4pxNVGhpcyBpcyBteSBzbmVha3kgcGxhaW50ZXh0IG1l
+c3NhZ2UKowGbwMvMwCSoW1RzPCOz3IRxTWISa6JebnG666MFD1wzSzJSixQ81XMV
+UlITUxTyixRyKxXKE0uSMxQyEosVikvyCwpSU/S4FNCArq6Ce1F+aXJGvoJvYlGF
+erFCTmJxiUJ5flFKMVeHGwuDIBMDGysTyA4GLk4BmO036xgWzMgzt9V85jCtfDFn
+UqVooWlGXHwNw/xg/fVzt9VNbtjtJ/fhUqYo0/LyCGEA
+=6+AK
+-----END PGP MESSAGE-----
+"""
+
+def check_result(result, summary, validity, fpr, status, notation):
+ assert len(result.signatures) == 1, "Unexpected number of signatures"
+ sig = result.signatures[0]
+ assert sig.summary == summary, \
+ "Unexpected signature summary: {}, want: {}".format(sig.summary,
+ summary)
+ assert sig.fpr == fpr
+ assert errors.GPGMEError(sig.status).getcode() == status
+
+ if notation:
+ expected_notations = {
+ "bar": (b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f" +
+ b" das waren Umlaute und jetzt ein prozent%-Zeichen"
+ if sys.version_info[0] < 3 else
+ b"\xc3\xb6\xc3\xa4\xc3\xbc\xc3\x9f".decode() +
+ " das waren Umlaute und jetzt ein prozent%-Zeichen"),
+ "foobar.1": "this is a notation data with 2 lines",
+ None: "http://www.gu.org/policy/",
+ }
+ assert len(sig.notations) == len(expected_notations)
+
+ for r in sig.notations:
+ assert not 'name_len' in dir(r)
+ assert not 'value_len' in dir(r)
+ assert r.name in expected_notations
+ assert r.value == expected_notations[r.name], \
+ "Expected {!r}, got {!r}".format(expected_notations[r.name],
+ r.value)
+ expected_notations.pop(r.name)
+
+ assert len(expected_notations) == 0
+
+ assert not sig.wrong_key_usage
+ assert sig.validity == validity, \
+ "Unexpected signature validity: {}, want: {}".format(
+ sig.validity, validity)
+ assert errors.GPGMEError(sig.validity_reason).getcode() == errors.NO_ERROR
+
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+# Checking a valid message.
+text = core.Data(test_text1)
+sig = core.Data(test_sig1)
+c.op_verify(sig, text, None)
+result = c.op_verify_result()
+check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ constants.VALIDITY_FULL,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR, True)
+
+
+# Checking a manipulated message.
+text = core.Data(test_text1f)
+sig.seek(0, os.SEEK_SET)
+c.op_verify(sig, text, None)
+result = c.op_verify_result()
+check_result(result, constants.SIGSUM_RED, constants.VALIDITY_UNKNOWN,
+ "2D727CC768697734", errors.BAD_SIGNATURE, False)
+
+# Checking a normal signature.
+text = core.Data()
+sig = core.Data(test_sig2)
+c.op_verify(sig, None, text)
+result = c.op_verify_result()
+check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ constants.VALIDITY_FULL,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR, False)
+
+# Checking an invalid message.
+text = core.Data()
+sig = core.Data(double_plaintext_sig)
+try:
+ c.op_verify(sig, None, text)
+except Exception as e:
+ assert type(e) == errors.GPGMEError
+ assert e.getcode() == errors.BAD_DATA
+else:
+ assert False, "Expected an error but got none."
+
+
+# Idiomatic interface.
+with pyme.Context(armor=True) as c:
+ # Checking a valid message.
+ _, result = c.verify(test_text1, test_sig1)
+ check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ constants.VALIDITY_FULL,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR, True)
+
+ # Checking a manipulated message.
+ try:
+ c.verify(test_text1f, test_sig1)
+ except errors.BadSignatures as e:
+ check_result(e.result, constants.SIGSUM_RED,
+ constants.VALIDITY_UNKNOWN,
+ "2D727CC768697734", errors.BAD_SIGNATURE, False)
+ else:
+ assert False, "Expected an error but got none."
+
+ # Checking a normal signature.
+ sig = core.Data(test_sig2)
+ data, result = c.verify(test_sig2)
+ check_result(result, constants.SIGSUM_VALID | constants.SIGSUM_GREEN,
+ constants.VALIDITY_FULL,
+ "A0FF4590BB6122EDEF6E3C542D727CC768697734",
+ errors.NO_ERROR, False)
+ assert data == test_text1
+
+ # Checking an invalid message.
+ try:
+ c.verify(double_plaintext_sig)
+ except errors.GPGMEError as e:
+ assert e.getcode() == errors.BAD_DATA
+ else:
+ assert False, "Expected an error but got none."
+
+ alpha = c.get_key("A0FF4590BB6122EDEF6E3C542D727CC768697734", False)
+ bob = c.get_key("D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2", False)
+
+ # Checking a valid message.
+ c.verify(test_text1, test_sig1, verify=[alpha])
+
+ try:
+ c.verify(test_text1, test_sig1, verify=[alpha, bob])
+ except errors.MissingSignatures as e:
+ assert len(e.missing) == 1
+ assert e.missing[0] == bob
+ else:
+ assert False, "Expected an error, got none"
diff --git a/lang/python/tests/t-wait.py b/lang/python/tests/t-wait.py
new file mode 100755
index 0000000..b7d9a34
--- /dev/null
+++ b/lang/python/tests/t-wait.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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
+
+import time
+from pyme import core, constants, errors
+import support
+
+support.init_gpgme(constants.PROTOCOL_OpenPGP)
+c = core.Context()
+c.set_armor(True)
+
+# Checking a message without a signature.
+sig = core.Data("foo\n")
+text = core.Data()
+c.op_verify_start(sig, None, text)
+
+try:
+ while True:
+ err = c.wait(False)
+ if err:
+ break
+ time.sleep(0.1)
+except Exception as e:
+ assert e.getcode() == errors.NO_DATA
+else:
+ assert False, "Expected an error, got none"
diff --git a/lang/python/tests/t-wrapper.py b/lang/python/tests/t-wrapper.py
new file mode 100755
index 0000000..d260264
--- /dev/null
+++ b/lang/python/tests/t-wrapper.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# 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 General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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 pyme import core
+
+d0 = core.Data()
+d0.seek # trigger on-demand-wrapping
+assert d0.seek == d0.seek, "Generated wrapper functions are not cached"
+assert hasattr(core.Data, 'seek'), "Generated wrapper functions are not shared"
diff --git a/lang/qt/Makefile.am b/lang/qt/Makefile.am
new file mode 100644
index 0000000..39eb55e
--- /dev/null
+++ b/lang/qt/Makefile.am
@@ -0,0 +1,23 @@
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+SUBDIRS = src tests doc
+
+EXTRA_DIST = README
diff --git a/lang/qt/Makefile.in b/lang/qt/Makefile.in
new file mode 100644
index 0000000..d8b48d2
--- /dev/null
+++ b/lang/qt/Makefile.in
@@ -0,0 +1,709 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/qt
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = src tests doc
+EXTRA_DIST = README
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/qt/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/qt/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/qt/README b/lang/qt/README
new file mode 100644
index 0000000..6360a5b
--- /dev/null
+++ b/lang/qt/README
@@ -0,0 +1,130 @@
+Qt API bindings/wrapper for GPGME
+---------------------------------
+Based on KF5gpgmepp QGpgME and libkleo/backends/qgpgme
+
+Please note that QGpgME has a different license (GPL only)
+then GPGME itself. See the License secion in this
+document for more information.
+
+Overview
+--------
+QGpgme provides a very high level Qt API around GpgMEpp.
+As such it depends on GpgMEpp additionally to GpgME.
+
+There are two general concepts in QGpgME. Data abstraction
+through GpgMEpp's Dataprovider interface and the Job pattern.
+
+Data can be provided with QByteArrayDataProvider or
+QIODeviceDataProvider which can be constructed from their
+respective types. This means you can pass a QFile, QProcess,
+QString, etc.. directly to GPGME.
+
+To provide a stable API / ABI and because of historic reasons
+in libkleo (Where QGpgME was originally developed as an abstract
+crypto backend) QGpgME only provides abstract interfaces as
+public API while the actual implementation happens in the
+private QGpgME prefixed classes.
+
+Usage
+-----
+
+To use QGpgME first you need to obtain a Protocol class
+either for CMS (S/MIME) or OpenPGP. This Protocol class
+can then be used to create a Job.
+
+Each Job can be started asynchronusly and emits a result
+signal when done. The jobs are deleted automatically
+with QObject::deleteLater so they can be started without
+result handlers.
+
+The result signal provides a tuple of objects with the
+appropiate result information for this job. For historic
+reasons each result signal also includes an AuditLog
+and an AuditLog Error. These are only useful for
+S/MIME signature validation but are part of other jobs
+for API stability reasons.
+
+Some jobs like the verification or decryption jobs have
+dedicated result classes. Each result class at least
+has the member function error() that can be used
+to check if a job failed. Additionally errors are emited
+in the result signal.
+
+Jobs also provide progress signal whenever GnuPG emits
+a progress status line.
+
+Most jobs also provide a way synchronusly execute them.
+Please not that synchronus use does not cause the autodeletion
+to take place so you have to manually delete them.
+
+Async usage:
+
+ /* Create a job */
+ EncryptJob *job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
+ /* Connect something to the result signal */
+ connect(job, &EncryptJob::result, this, [] (const GpgME::EncryptionResult &result,
+ const QByteArray &cipherText,
+ const QString,
+ const GpgME::Error) {
+ /* Handle the result / do something with the ciphertext */
+ });
+ /* Start the job */
+ job->start(keys, inptr, outptr, Context::AlwaysTrust);
+ /* Do not delete the job as it is autodeleted. */
+
+Syncronus usage:
+
+ /* Create a job */
+ KeyListJob *listjob = openpgp()->keyListJob(false, false, false);
+ /* Prepare result vector */
+ std::vector<Key> keys;
+ /* Execute it synchronusly */
+ KeyListResult result = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ /* Delete the job */
+ delete listjob;
+ /* Work with the result */
+
+See the generated documentation for more info on the classes
+in QGpgME. (Subdir doc)
+
+Examples / Tests
+----------------
+
+The tests in the tests subdir can be used to get a better
+idea of QGpgME's usage. They also serve to test the C++
+API. Kleopatra and KMails Messagelib also make extensive
+use of QGpgME and can be used as further examples.
+
+Hacking
+-------
+QGpgME comes from a KDE background. As such it does not use
+GNU Coding styles but KDE Coding styles. See:
+https://techbase.kde.org/Policies/Frameworks_Coding_Style
+
+License
+-------
+QGpgME is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+QGpgME is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+In addition, as a special exception, the copyright holders give
+permission to link the code of this program with any edition of
+the Qt library by Trolltech AS, Norway (or with modified versions
+of Qt that use the same license as Qt), and distribute linked
+combinations including the two. You must obey the GNU General
+Public License in all respects for all of the code used other than
+Qt. If you modify this file, you may extend this exception to
+your version of the file, but you are not obligated to do so. If
+you do not wish to do so, delete this exception statement from
+your version.
diff --git a/lang/qt/doc/Doxyfile.in b/lang/qt/doc/Doxyfile.in
new file mode 100644
index 0000000..5d94f90
--- /dev/null
+++ b/lang/qt/doc/Doxyfile.in
@@ -0,0 +1,2352 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "QGpgME"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = "@LIBQGPGME_LT_CURRENT@.@LIBQGPGME_LT_AGE@.@LIBQGPGME_LT_REVISION@.@BUILD_REVISION@"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Qt API for GpgME"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = "@abs_builddir@/generated"
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = "@top_srcdir@/lang/qt/src"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = @HAVE_DOT@
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/lang/qt/doc/Makefile.am b/lang/qt/doc/Makefile.am
new file mode 100644
index 0000000..ddf4935
--- /dev/null
+++ b/lang/qt/doc/Makefile.am
@@ -0,0 +1,31 @@
+# Makefile.am - Makefile for GPGME Qt docs.
+# Copyright (C) 2016 Intevation 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/>.
+
+## Process this file with automake to produce Makefile.in
+
+if HAVE_DOXYGEN
+doxyfile.stamp:
+ $(DOXYGEN) Doxyfile
+ touch doxyfile.stamp
+
+CLEANFILES = doxyfile.stamp
+
+all-local: doxyfile.stamp
+clean-local:
+ rm -rf $(abs_builddir)/generated
+endif
diff --git a/lang/qt/doc/Makefile.in b/lang/qt/doc/Makefile.in
new file mode 100644
index 0000000..d6d9ef7
--- /dev/null
+++ b/lang/qt/doc/Makefile.in
@@ -0,0 +1,540 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am - Makefile for GPGME Qt docs.
+# Copyright (C) 2016 Intevation 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/>.
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/qt/doc
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs $(srcdir)/Doxyfile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = Doxyfile
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@HAVE_DOXYGEN_TRUE@CLEANFILES = doxyfile.stamp
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/qt/doc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/qt/doc/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+@HAVE_DOXYGEN_TRUE@Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in
+@HAVE_DOXYGEN_TRUE@ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+@HAVE_DOXYGEN_FALSE@all-local:
+all-am: Makefile all-local
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+@HAVE_DOXYGEN_FALSE@clean-local:
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am all-local check check-am clean clean-generic \
+ clean-libtool clean-local cscopelist-am ctags-am distclean \
+ distclean-generic distclean-libtool distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am
+
+
+@HAVE_DOXYGEN_TRUE@doxyfile.stamp:
+@HAVE_DOXYGEN_TRUE@ $(DOXYGEN) Doxyfile
+@HAVE_DOXYGEN_TRUE@ touch doxyfile.stamp
+
+@HAVE_DOXYGEN_TRUE@all-local: doxyfile.stamp
+@HAVE_DOXYGEN_TRUE@clean-local:
+@HAVE_DOXYGEN_TRUE@ rm -rf $(abs_builddir)/generated
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/qt/src/AddUserIDJob b/lang/qt/src/AddUserIDJob
new file mode 100644
index 0000000..87d82ec
--- /dev/null
+++ b/lang/qt/src/AddUserIDJob
@@ -0,0 +1 @@
+#include "qgpgme/adduseridjob.h"
diff --git a/lang/qt/src/ChangeExpiryJob b/lang/qt/src/ChangeExpiryJob
new file mode 100644
index 0000000..f5eea6a
--- /dev/null
+++ b/lang/qt/src/ChangeExpiryJob
@@ -0,0 +1 @@
+#include "qgpgme/changeexpiryjob.h"
diff --git a/lang/qt/src/ChangeOwnerTrustJob b/lang/qt/src/ChangeOwnerTrustJob
new file mode 100644
index 0000000..03635d5
--- /dev/null
+++ b/lang/qt/src/ChangeOwnerTrustJob
@@ -0,0 +1 @@
+#include "qgpgme/changeownertrustjob.h"
diff --git a/lang/qt/src/ChangePasswdJob b/lang/qt/src/ChangePasswdJob
new file mode 100644
index 0000000..3660940
--- /dev/null
+++ b/lang/qt/src/ChangePasswdJob
@@ -0,0 +1 @@
+#include "qgpgme/changepasswdjob.h"
diff --git a/lang/qt/src/CryptoConfig b/lang/qt/src/CryptoConfig
new file mode 100644
index 0000000..4edbd19
--- /dev/null
+++ b/lang/qt/src/CryptoConfig
@@ -0,0 +1 @@
+#include "qgpgme/cryptoconfig.h"
diff --git a/lang/qt/src/DataProvider b/lang/qt/src/DataProvider
new file mode 100644
index 0000000..6a43c1d
--- /dev/null
+++ b/lang/qt/src/DataProvider
@@ -0,0 +1 @@
+#include "qgpgme/dataprovider.h"
diff --git a/lang/qt/src/DecryptJob b/lang/qt/src/DecryptJob
new file mode 100644
index 0000000..c0f9845
--- /dev/null
+++ b/lang/qt/src/DecryptJob
@@ -0,0 +1 @@
+#include "qgpgme/decryptjob.h"
diff --git a/lang/qt/src/DecryptVerifyJob b/lang/qt/src/DecryptVerifyJob
new file mode 100644
index 0000000..e3de1cc
--- /dev/null
+++ b/lang/qt/src/DecryptVerifyJob
@@ -0,0 +1 @@
+#include "qgpgme/decryptverifyjob.h"
diff --git a/lang/qt/src/DefaultKeyGenerationJob b/lang/qt/src/DefaultKeyGenerationJob
new file mode 100644
index 0000000..1dc8c40
--- /dev/null
+++ b/lang/qt/src/DefaultKeyGenerationJob
@@ -0,0 +1 @@
+#include "qgpgme/defaultkeygenerationjob.h"
diff --git a/lang/qt/src/DeleteJob b/lang/qt/src/DeleteJob
new file mode 100644
index 0000000..a2fdc4a
--- /dev/null
+++ b/lang/qt/src/DeleteJob
@@ -0,0 +1 @@
+#include "qgpgme/deletejob.h"
diff --git a/lang/qt/src/DownloadJob b/lang/qt/src/DownloadJob
new file mode 100644
index 0000000..9b47aac
--- /dev/null
+++ b/lang/qt/src/DownloadJob
@@ -0,0 +1 @@
+#include "qgpgme/downloadjob.h"
diff --git a/lang/qt/src/EncryptJob b/lang/qt/src/EncryptJob
new file mode 100644
index 0000000..59a878d
--- /dev/null
+++ b/lang/qt/src/EncryptJob
@@ -0,0 +1 @@
+#include "qgpgme/encryptjob.h"
diff --git a/lang/qt/src/ExportJob b/lang/qt/src/ExportJob
new file mode 100644
index 0000000..1d053fd
--- /dev/null
+++ b/lang/qt/src/ExportJob
@@ -0,0 +1 @@
+#include "qgpgme/exportjob.h"
diff --git a/lang/qt/src/HierarchicalKeyKistJob b/lang/qt/src/HierarchicalKeyKistJob
new file mode 100644
index 0000000..cd31f48
--- /dev/null
+++ b/lang/qt/src/HierarchicalKeyKistJob
@@ -0,0 +1 @@
+#include "qgpgme/hierarchicalkeykistjob.h"
diff --git a/lang/qt/src/ImportFromKeyserverJob b/lang/qt/src/ImportFromKeyserverJob
new file mode 100644
index 0000000..17a5fd6
--- /dev/null
+++ b/lang/qt/src/ImportFromKeyserverJob
@@ -0,0 +1 @@
+#include "qgpgme/importfromkeyserverjob.h"
diff --git a/lang/qt/src/ImportJob b/lang/qt/src/ImportJob
new file mode 100644
index 0000000..e5228d7
--- /dev/null
+++ b/lang/qt/src/ImportJob
@@ -0,0 +1 @@
+#include "qgpgme/importjob.h"
diff --git a/lang/qt/src/Job b/lang/qt/src/Job
new file mode 100644
index 0000000..3a45ca7
--- /dev/null
+++ b/lang/qt/src/Job
@@ -0,0 +1 @@
+#include "qgpgme/job.h"
diff --git a/lang/qt/src/KeyForMailboxJob b/lang/qt/src/KeyForMailboxJob
new file mode 100644
index 0000000..2d2b8cb
--- /dev/null
+++ b/lang/qt/src/KeyForMailboxJob
@@ -0,0 +1 @@
+#include "qgpgme/keyformailboxjob.h"
diff --git a/lang/qt/src/KeyGenerationJob b/lang/qt/src/KeyGenerationJob
new file mode 100644
index 0000000..1612ba7
--- /dev/null
+++ b/lang/qt/src/KeyGenerationJob
@@ -0,0 +1 @@
+#include "qgpgme/keygenerationjob.h"
diff --git a/lang/qt/src/KeyListJob b/lang/qt/src/KeyListJob
new file mode 100644
index 0000000..7366665
--- /dev/null
+++ b/lang/qt/src/KeyListJob
@@ -0,0 +1 @@
+#include "qgpgme/keylistjob.h"
diff --git a/lang/qt/src/ListAllKeysJob b/lang/qt/src/ListAllKeysJob
new file mode 100644
index 0000000..8023f8f
--- /dev/null
+++ b/lang/qt/src/ListAllKeysJob
@@ -0,0 +1 @@
+#include "qgpgme/listallkeysjob.h"
diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am
new file mode 100644
index 0000000..c15da18
--- /dev/null
+++ b/lang/qt/src/Makefile.am
@@ -0,0 +1,256 @@
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+lib_LTLIBRARIES = libqgpgme.la
+EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in \
+ gpgme_backend_debug.h qgpgme_version.h.in
+
+qgpgme_sources = \
+ dataprovider.cpp job.cpp qgpgmeadduseridjob.cpp \
+ qgpgmebackend.cpp qgpgmechangeexpiryjob.cpp qgpgmechangeownertrustjob.cpp \
+ qgpgmechangepasswdjob.cpp qgpgmedecryptjob.cpp \
+ qgpgmedecryptverifyjob.cpp qgpgmedeletejob.cpp qgpgmedownloadjob.cpp \
+ qgpgmeencryptjob.cpp qgpgmeexportjob.cpp qgpgmeimportfromkeyserverjob.cpp \
+ qgpgmeimportjob.cpp qgpgmekeygenerationjob.cpp qgpgmekeylistjob.cpp \
+ qgpgmelistallkeysjob.cpp qgpgmenewcryptoconfig.cpp \
+ qgpgmerefreshkeysjob.cpp \
+ qgpgmesecretkeyexportjob.cpp qgpgmesignencryptjob.cpp \
+ qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \
+ qgpgmeverifyopaquejob.cpp threadedjobmixin.cpp \
+ qgpgmekeyformailboxjob.cpp gpgme_backend_debug.cpp \
+ qgpgmetofupolicyjob.cpp \
+ defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp
+
+# If you add one here make sure that you also add one in camelcase
+qgpgme_headers= \
+ adduseridjob.h \
+ changeexpiryjob.h \
+ changeownertrustjob.h \
+ changepasswdjob.h \
+ dataprovider.h \
+ decryptjob.h \
+ decryptverifyjob.h \
+ downloadjob.h \
+ encryptjob.h \
+ exportjob.h \
+ hierarchicalkeylistjob.h \
+ job.h \
+ keyformailboxjob.h \
+ multideletejob.h \
+ protocol.h \
+ qgpgme_export.h \
+ qgpgmenewcryptoconfig.h \
+ signjob.h \
+ signkeyjob.h \
+ signencryptjob.h \
+ verifyopaquejob.h \
+ refreshkeysjob.h \
+ cryptoconfig.h \
+ deletejob.h \
+ importfromkeyserverjob.h \
+ importjob.h \
+ keygenerationjob.h \
+ keylistjob.h \
+ listallkeysjob.h \
+ verifydetachedjob.h \
+ defaultkeygenerationjob.h \
+ tofupolicyjob.h \
+ wkspublishjob.h
+
+camelcase_headers= \
+ AddUserIDJob \
+ ChangeExpiryJob \
+ ChangeOwnerTrustJob \
+ ChangePasswdJob \
+ DataProvider \
+ DecryptJob \
+ DecryptVerifyJob \
+ DownloadJob \
+ EncryptJob \
+ ExportJob \
+ HierarchicalKeyKistJob \
+ Job \
+ MultiDeleteJob \
+ Protocol \
+ QGpgMENewCryptoConfig \
+ SignJob \
+ SignKeyJob \
+ SignEncryptJob \
+ VerifyOpaqueJob \
+ RefreshKeysJob \
+ CryptoConfig \
+ DeleteJob \
+ ImportFromKeyserverJob \
+ ImportJob \
+ KeyGenerationJob \
+ KeyListJob \
+ ListAllKeysJob \
+ VerifyDetachedJob \
+ KeyForMailboxJob \
+ DefaultKeyGenerationJob \
+ WKSPublishJob \
+ TofuPolicyJob
+
+private_qgpgme_headers = \
+ qgpgme_export.h \
+ abstractimportjob.h \
+ protocol_p.h \
+ qgpgmeadduseridjob.h \
+ qgpgmebackend.h \
+ qgpgmechangeexpiryjob.h \
+ qgpgmechangeownertrustjob.h \
+ qgpgmechangepasswdjob.h \
+ qgpgmedecryptjob.h \
+ qgpgmedecryptverifyjob.h \
+ qgpgmedeletejob.h \
+ qgpgmedownloadjob.h \
+ qgpgmeencryptjob.h \
+ qgpgmeexportjob.h \
+ qgpgmeimportfromkeyserverjob.h \
+ qgpgmeimportjob.h \
+ qgpgmekeygenerationjob.h \
+ qgpgmekeylistjob.h \
+ qgpgmelistallkeysjob.h \
+ qgpgmerefreshkeysjob.h \
+ qgpgmesecretkeyexportjob.h \
+ qgpgmesignencryptjob.h \
+ qgpgmesignjob.h \
+ qgpgmesignkeyjob.h \
+ qgpgmeverifydetachedjob.h \
+ qgpgmeverifyopaquejob.h \
+ qgpgmekeyformailboxjob.h \
+ qgpgmewkspublishjob.h \
+ qgpgmetofupolicyjob.h \
+ specialjob.h \
+ threadedjobmixin.h
+
+qgpgme_moc_sources = \
+ abstractimportjob.moc \
+ adduseridjob.moc \
+ changeexpiryjob.moc \
+ changeownertrustjob.moc \
+ changepasswdjob.moc \
+ decryptjob.moc \
+ decryptverifyjob.moc \
+ deletejob.moc \
+ downloadjob.moc \
+ encryptjob.moc \
+ exportjob.moc \
+ hierarchicalkeylistjob.moc \
+ importfromkeyserverjob.moc \
+ importjob.moc \
+ job.moc \
+ keygenerationjob.moc \
+ keylistjob.moc \
+ listallkeysjob.moc \
+ multideletejob.moc \
+ qgpgmeadduseridjob.moc \
+ qgpgmechangeexpiryjob.moc \
+ qgpgmechangeownertrustjob.moc \
+ qgpgmechangepasswdjob.moc \
+ qgpgmedecryptjob.moc \
+ qgpgmedecryptverifyjob.moc \
+ qgpgmedeletejob.moc \
+ qgpgmedownloadjob.moc \
+ qgpgmeencryptjob.moc \
+ qgpgmeexportjob.moc \
+ qgpgmeimportfromkeyserverjob.moc \
+ qgpgmeimportjob.moc \
+ qgpgmekeygenerationjob.moc \
+ qgpgmekeylistjob.moc \
+ qgpgmelistallkeysjob.moc \
+ qgpgmerefreshkeysjob.moc \
+ qgpgmesecretkeyexportjob.moc \
+ qgpgmesignencryptjob.moc \
+ qgpgmesignjob.moc \
+ qgpgmesignkeyjob.moc \
+ qgpgmeverifydetachedjob.moc \
+ qgpgmeverifyopaquejob.moc \
+ qgpgmewkspublishjob.moc \
+ tofupolicyjob.moc \
+ qgpgmetofupolicyjob.moc \
+ refreshkeysjob.moc \
+ signencryptjob.moc \
+ signjob.moc \
+ signkeyjob.moc \
+ specialjob.moc \
+ verifydetachedjob.moc \
+ verifyopaquejob.moc \
+ keyformailboxjob.moc \
+ wkspublishjob.moc \
+ qgpgmekeyformailboxjob.moc \
+ defaultkeygenerationjob.moc
+
+qgpgmeincludedir = $(includedir)/qgpgme
+qgpgmeinclude_HEADERS = $(qgpgme_headers)
+camelcaseincludedir = $(includedir)/QGpgME
+camelcaseinclude_HEADERS = $(camelcase_headers)
+nodist_include_HEADERS = qgpgme_version.h
+
+libqgpgme_la_SOURCES = $(qgpgme_sources) $(qgpgme_headers) $(private_qgpgme_headers)
+
+AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
+ @GPGME_QT_CFLAGS@ @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
+ -DBUILDING_QGPGME
+
+libqgpgme_la_LIBADD = ../../cpp/src/libgpgmepp.la ../../../src/libgpgme.la \
+ @LIBASSUAN_LIBS@ @GPGME_QT_LIBS@
+libqgpgme_la_LDFLAGS = -version-info \
+ @LIBQGPGME_LT_CURRENT@:@LIBQGPGME_LT_REVISION@:@LIBQGPGME_LT_AGE@
+
+if HAVE_W32_SYSTEM
+libsuffix=.dll.a
+else
+libsuffix=.so
+endif
+
+QGpgmeConfig.cmake: QGpgmeConfig.cmake.in
+ sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@"
+ sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2
+ mv "$@".2 "$@"
+
+$(camelcase_headers): Makefile.am
+ echo -n "#include \"qgpgme/" > "$@"
+ echo -n "$@" | tr '[:upper:]' '[:lower:]' >> "$@"
+ echo ".h\"" >> "$@"
+
+install-cmake-files: QGpgmeConfig.cmake QGpgmeConfigVersion.cmake
+ -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp
+ $(INSTALL) QGpgmeConfig.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake
+ $(INSTALL) QGpgmeConfigVersion.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake
+
+uninstall-cmake-files:
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake
+ -rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/
+
+install-data-local: install-cmake-files
+
+uninstall-local: uninstall-cmake-files
+
+BUILT_SOURCES = $(qgpgme_moc_sources) $(camelcase_headers)
+
+CLEANFILES = $(qgpgme_moc_sources) $(camelcase_headers) QGpgmeConfig.cmake
+
+nodist_libqgpgme_la_SOURCES = $(qgpgme_moc_sources)
+
+.h.moc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
diff --git a/lang/qt/src/Makefile.in b/lang/qt/src/Makefile.in
new file mode 100644
index 0000000..d10eca3
--- /dev/null
+++ b/lang/qt/src/Makefile.in
@@ -0,0 +1,1123 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lang/qt/src
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs \
+ $(srcdir)/QGpgmeConfig.cmake.in.in \
+ $(srcdir)/QGpgmeConfigVersion.cmake.in \
+ $(srcdir)/qgpgme_version.h.in $(top_srcdir)/build-aux/depcomp \
+ $(camelcaseinclude_HEADERS) $(qgpgmeinclude_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = QGpgmeConfig.cmake.in QGpgmeConfigVersion.cmake \
+ qgpgme_version.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(camelcaseincludedir)" "$(DESTDIR)$(includedir)" \
+ "$(DESTDIR)$(qgpgmeincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libqgpgme_la_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../../../src/libgpgme.la
+am__objects_1 = dataprovider.lo job.lo qgpgmeadduseridjob.lo \
+ qgpgmebackend.lo qgpgmechangeexpiryjob.lo \
+ qgpgmechangeownertrustjob.lo qgpgmechangepasswdjob.lo \
+ qgpgmedecryptjob.lo qgpgmedecryptverifyjob.lo \
+ qgpgmedeletejob.lo qgpgmedownloadjob.lo qgpgmeencryptjob.lo \
+ qgpgmeexportjob.lo qgpgmeimportfromkeyserverjob.lo \
+ qgpgmeimportjob.lo qgpgmekeygenerationjob.lo \
+ qgpgmekeylistjob.lo qgpgmelistallkeysjob.lo \
+ qgpgmenewcryptoconfig.lo qgpgmerefreshkeysjob.lo \
+ qgpgmesecretkeyexportjob.lo qgpgmesignencryptjob.lo \
+ qgpgmesignjob.lo qgpgmesignkeyjob.lo \
+ qgpgmeverifydetachedjob.lo qgpgmeverifyopaquejob.lo \
+ threadedjobmixin.lo qgpgmekeyformailboxjob.lo \
+ gpgme_backend_debug.lo qgpgmetofupolicyjob.lo \
+ defaultkeygenerationjob.lo qgpgmewkspublishjob.lo
+am__objects_2 =
+am_libqgpgme_la_OBJECTS = $(am__objects_1) $(am__objects_2) \
+ $(am__objects_2)
+nodist_libqgpgme_la_OBJECTS = $(am__objects_2)
+libqgpgme_la_OBJECTS = $(am_libqgpgme_la_OBJECTS) \
+ $(nodist_libqgpgme_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libqgpgme_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libqgpgme_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libqgpgme_la_SOURCES) $(nodist_libqgpgme_la_SOURCES)
+DIST_SOURCES = $(libqgpgme_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(camelcaseinclude_HEADERS) $(nodist_include_HEADERS) \
+ $(qgpgmeinclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Makefile.am for GPGMEPP.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGMEPP.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+lib_LTLIBRARIES = libqgpgme.la
+EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in \
+ gpgme_backend_debug.h qgpgme_version.h.in
+
+qgpgme_sources = \
+ dataprovider.cpp job.cpp qgpgmeadduseridjob.cpp \
+ qgpgmebackend.cpp qgpgmechangeexpiryjob.cpp qgpgmechangeownertrustjob.cpp \
+ qgpgmechangepasswdjob.cpp qgpgmedecryptjob.cpp \
+ qgpgmedecryptverifyjob.cpp qgpgmedeletejob.cpp qgpgmedownloadjob.cpp \
+ qgpgmeencryptjob.cpp qgpgmeexportjob.cpp qgpgmeimportfromkeyserverjob.cpp \
+ qgpgmeimportjob.cpp qgpgmekeygenerationjob.cpp qgpgmekeylistjob.cpp \
+ qgpgmelistallkeysjob.cpp qgpgmenewcryptoconfig.cpp \
+ qgpgmerefreshkeysjob.cpp \
+ qgpgmesecretkeyexportjob.cpp qgpgmesignencryptjob.cpp \
+ qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \
+ qgpgmeverifyopaquejob.cpp threadedjobmixin.cpp \
+ qgpgmekeyformailboxjob.cpp gpgme_backend_debug.cpp \
+ qgpgmetofupolicyjob.cpp \
+ defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp
+
+
+# If you add one here make sure that you also add one in camelcase
+qgpgme_headers = \
+ adduseridjob.h \
+ changeexpiryjob.h \
+ changeownertrustjob.h \
+ changepasswdjob.h \
+ dataprovider.h \
+ decryptjob.h \
+ decryptverifyjob.h \
+ downloadjob.h \
+ encryptjob.h \
+ exportjob.h \
+ hierarchicalkeylistjob.h \
+ job.h \
+ keyformailboxjob.h \
+ multideletejob.h \
+ protocol.h \
+ qgpgme_export.h \
+ qgpgmenewcryptoconfig.h \
+ signjob.h \
+ signkeyjob.h \
+ signencryptjob.h \
+ verifyopaquejob.h \
+ refreshkeysjob.h \
+ cryptoconfig.h \
+ deletejob.h \
+ importfromkeyserverjob.h \
+ importjob.h \
+ keygenerationjob.h \
+ keylistjob.h \
+ listallkeysjob.h \
+ verifydetachedjob.h \
+ defaultkeygenerationjob.h \
+ tofupolicyjob.h \
+ wkspublishjob.h
+
+camelcase_headers = \
+ AddUserIDJob \
+ ChangeExpiryJob \
+ ChangeOwnerTrustJob \
+ ChangePasswdJob \
+ DataProvider \
+ DecryptJob \
+ DecryptVerifyJob \
+ DownloadJob \
+ EncryptJob \
+ ExportJob \
+ HierarchicalKeyKistJob \
+ Job \
+ MultiDeleteJob \
+ Protocol \
+ QGpgMENewCryptoConfig \
+ SignJob \
+ SignKeyJob \
+ SignEncryptJob \
+ VerifyOpaqueJob \
+ RefreshKeysJob \
+ CryptoConfig \
+ DeleteJob \
+ ImportFromKeyserverJob \
+ ImportJob \
+ KeyGenerationJob \
+ KeyListJob \
+ ListAllKeysJob \
+ VerifyDetachedJob \
+ KeyForMailboxJob \
+ DefaultKeyGenerationJob \
+ WKSPublishJob \
+ TofuPolicyJob
+
+private_qgpgme_headers = \
+ qgpgme_export.h \
+ abstractimportjob.h \
+ protocol_p.h \
+ qgpgmeadduseridjob.h \
+ qgpgmebackend.h \
+ qgpgmechangeexpiryjob.h \
+ qgpgmechangeownertrustjob.h \
+ qgpgmechangepasswdjob.h \
+ qgpgmedecryptjob.h \
+ qgpgmedecryptverifyjob.h \
+ qgpgmedeletejob.h \
+ qgpgmedownloadjob.h \
+ qgpgmeencryptjob.h \
+ qgpgmeexportjob.h \
+ qgpgmeimportfromkeyserverjob.h \
+ qgpgmeimportjob.h \
+ qgpgmekeygenerationjob.h \
+ qgpgmekeylistjob.h \
+ qgpgmelistallkeysjob.h \
+ qgpgmerefreshkeysjob.h \
+ qgpgmesecretkeyexportjob.h \
+ qgpgmesignencryptjob.h \
+ qgpgmesignjob.h \
+ qgpgmesignkeyjob.h \
+ qgpgmeverifydetachedjob.h \
+ qgpgmeverifyopaquejob.h \
+ qgpgmekeyformailboxjob.h \
+ qgpgmewkspublishjob.h \
+ qgpgmetofupolicyjob.h \
+ specialjob.h \
+ threadedjobmixin.h
+
+qgpgme_moc_sources = \
+ abstractimportjob.moc \
+ adduseridjob.moc \
+ changeexpiryjob.moc \
+ changeownertrustjob.moc \
+ changepasswdjob.moc \
+ decryptjob.moc \
+ decryptverifyjob.moc \
+ deletejob.moc \
+ downloadjob.moc \
+ encryptjob.moc \
+ exportjob.moc \
+ hierarchicalkeylistjob.moc \
+ importfromkeyserverjob.moc \
+ importjob.moc \
+ job.moc \
+ keygenerationjob.moc \
+ keylistjob.moc \
+ listallkeysjob.moc \
+ multideletejob.moc \
+ qgpgmeadduseridjob.moc \
+ qgpgmechangeexpiryjob.moc \
+ qgpgmechangeownertrustjob.moc \
+ qgpgmechangepasswdjob.moc \
+ qgpgmedecryptjob.moc \
+ qgpgmedecryptverifyjob.moc \
+ qgpgmedeletejob.moc \
+ qgpgmedownloadjob.moc \
+ qgpgmeencryptjob.moc \
+ qgpgmeexportjob.moc \
+ qgpgmeimportfromkeyserverjob.moc \
+ qgpgmeimportjob.moc \
+ qgpgmekeygenerationjob.moc \
+ qgpgmekeylistjob.moc \
+ qgpgmelistallkeysjob.moc \
+ qgpgmerefreshkeysjob.moc \
+ qgpgmesecretkeyexportjob.moc \
+ qgpgmesignencryptjob.moc \
+ qgpgmesignjob.moc \
+ qgpgmesignkeyjob.moc \
+ qgpgmeverifydetachedjob.moc \
+ qgpgmeverifyopaquejob.moc \
+ qgpgmewkspublishjob.moc \
+ tofupolicyjob.moc \
+ qgpgmetofupolicyjob.moc \
+ refreshkeysjob.moc \
+ signencryptjob.moc \
+ signjob.moc \
+ signkeyjob.moc \
+ specialjob.moc \
+ verifydetachedjob.moc \
+ verifyopaquejob.moc \
+ keyformailboxjob.moc \
+ wkspublishjob.moc \
+ qgpgmekeyformailboxjob.moc \
+ defaultkeygenerationjob.moc
+
+qgpgmeincludedir = $(includedir)/qgpgme
+qgpgmeinclude_HEADERS = $(qgpgme_headers)
+camelcaseincludedir = $(includedir)/QGpgME
+camelcaseinclude_HEADERS = $(camelcase_headers)
+nodist_include_HEADERS = qgpgme_version.h
+libqgpgme_la_SOURCES = $(qgpgme_sources) $(qgpgme_headers) $(private_qgpgme_headers)
+AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
+ @GPGME_QT_CFLAGS@ @GPG_ERROR_CFLAGS@ @LIBASSUAN_CFLAGS@ \
+ -DBUILDING_QGPGME
+
+libqgpgme_la_LIBADD = ../../cpp/src/libgpgmepp.la ../../../src/libgpgme.la \
+ @LIBASSUAN_LIBS@ @GPGME_QT_LIBS@
+
+libqgpgme_la_LDFLAGS = -version-info \
+ @LIBQGPGME_LT_CURRENT@:@LIBQGPGME_LT_REVISION@:@LIBQGPGME_LT_AGE@
+
+@HAVE_W32_SYSTEM_FALSE@libsuffix = .so
+@HAVE_W32_SYSTEM_TRUE@libsuffix = .dll.a
+BUILT_SOURCES = $(qgpgme_moc_sources) $(camelcase_headers)
+CLEANFILES = $(qgpgme_moc_sources) $(camelcase_headers) QGpgmeConfig.cmake
+nodist_libqgpgme_la_SOURCES = $(qgpgme_moc_sources)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .h .lo .moc .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/qt/src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/qt/src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+QGpgmeConfig.cmake.in: $(top_builddir)/config.status $(srcdir)/QGpgmeConfig.cmake.in.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+QGpgmeConfigVersion.cmake: $(top_builddir)/config.status $(srcdir)/QGpgmeConfigVersion.cmake.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+qgpgme_version.h: $(top_builddir)/config.status $(srcdir)/qgpgme_version.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libqgpgme.la: $(libqgpgme_la_OBJECTS) $(libqgpgme_la_DEPENDENCIES) $(EXTRA_libqgpgme_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libqgpgme_la_LINK) -rpath $(libdir) $(libqgpgme_la_OBJECTS) $(libqgpgme_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dataprovider.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defaultkeygenerationjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgme_backend_debug.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeadduseridjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmebackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmechangeexpiryjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmechangeownertrustjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmechangepasswdjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmedecryptjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmedecryptverifyjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmedeletejob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmedownloadjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeencryptjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeexportjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeimportfromkeyserverjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeimportjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmekeyformailboxjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmekeygenerationjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmekeylistjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmelistallkeysjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmenewcryptoconfig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmerefreshkeysjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmesecretkeyexportjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmesignencryptjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmesignjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmesignkeyjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmetofupolicyjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeverifydetachedjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmeverifyopaquejob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qgpgmewkspublishjob.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threadedjobmixin.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-camelcaseincludeHEADERS: $(camelcaseinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(camelcaseinclude_HEADERS)'; test -n "$(camelcaseincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(camelcaseincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(camelcaseincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(camelcaseincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(camelcaseincludedir)" || exit $$?; \
+ done
+
+uninstall-camelcaseincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(camelcaseinclude_HEADERS)'; test -n "$(camelcaseincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(camelcaseincludedir)'; $(am__uninstall_files_from_dir)
+install-nodist_includeHEADERS: $(nodist_include_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-nodist_includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+install-qgpgmeincludeHEADERS: $(qgpgmeinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(qgpgmeinclude_HEADERS)'; test -n "$(qgpgmeincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(qgpgmeincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(qgpgmeincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(qgpgmeincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(qgpgmeincludedir)" || exit $$?; \
+ done
+
+uninstall-qgpgmeincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(qgpgmeinclude_HEADERS)'; test -n "$(qgpgmeincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(qgpgmeincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(camelcaseincludedir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(qgpgmeincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-camelcaseincludeHEADERS install-data-local \
+ install-nodist_includeHEADERS install-qgpgmeincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-camelcaseincludeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-local \
+ uninstall-nodist_includeHEADERS uninstall-qgpgmeincludeHEADERS
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am \
+ install-camelcaseincludeHEADERS install-data install-data-am \
+ install-data-local install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-nodist_includeHEADERS install-pdf install-pdf-am \
+ install-ps install-ps-am install-qgpgmeincludeHEADERS \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-camelcaseincludeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-local uninstall-nodist_includeHEADERS \
+ uninstall-qgpgmeincludeHEADERS
+
+
+QGpgmeConfig.cmake: QGpgmeConfig.cmake.in
+ sed -e 's|[@]resolved_libdir@|$(libdir)|g' < "$<" > "$@"
+ sed -e 's|[@]libsuffix@|$(libsuffix)|g' < "$@" > "$@".2
+ mv "$@".2 "$@"
+
+$(camelcase_headers): Makefile.am
+ echo -n "#include \"qgpgme/" > "$@"
+ echo -n "$@" | tr '[:upper:]' '[:lower:]' >> "$@"
+ echo ".h\"" >> "$@"
+
+install-cmake-files: QGpgmeConfig.cmake QGpgmeConfigVersion.cmake
+ -$(INSTALL) -d $(DESTDIR)$(libdir)/cmake/Gpgmepp
+ $(INSTALL) QGpgmeConfig.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake
+ $(INSTALL) QGpgmeConfigVersion.cmake \
+ $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake
+
+uninstall-cmake-files:
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfigVersion.cmake
+ -rm $(DESTDIR)$(libdir)/cmake/Gpgmepp/QGpgmeConfig.cmake
+ -rmdir $(DESTDIR)$(libdir)/cmake/Gpgmepp/
+
+install-data-local: install-cmake-files
+
+uninstall-local: uninstall-cmake-files
+
+.h.moc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/qt/src/MultiDeleteJob b/lang/qt/src/MultiDeleteJob
new file mode 100644
index 0000000..e398c79
--- /dev/null
+++ b/lang/qt/src/MultiDeleteJob
@@ -0,0 +1 @@
+#include "qgpgme/multideletejob.h"
diff --git a/lang/qt/src/Protocol b/lang/qt/src/Protocol
new file mode 100644
index 0000000..6f92b75
--- /dev/null
+++ b/lang/qt/src/Protocol
@@ -0,0 +1 @@
+#include "qgpgme/protocol.h"
diff --git a/lang/qt/src/QGpgMENewCryptoConfig b/lang/qt/src/QGpgMENewCryptoConfig
new file mode 100644
index 0000000..99f353f
--- /dev/null
+++ b/lang/qt/src/QGpgMENewCryptoConfig
@@ -0,0 +1 @@
+#include "qgpgme/qgpgmenewcryptoconfig.h"
diff --git a/lang/qt/src/QGpgmeConfig.cmake.in.in b/lang/qt/src/QGpgmeConfig.cmake.in.in
new file mode 100644
index 0000000..3d19696
--- /dev/null
+++ b/lang/qt/src/QGpgmeConfig.cmake.in.in
@@ -0,0 +1,107 @@
+# CMake Config file for QGPGME.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGME.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+# based on a generated file from cmake.
+# Generated by CMake 3.0.2
+
+if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
+ message(FATAL_ERROR "CMake >= 2.6.0 required")
+endif()
+cmake_policy(PUSH)
+cmake_policy(VERSION 2.6)
+#----------------------------------------------------------------
+# Generated CMake target import file.
+#----------------------------------------------------------------
+
+# Commands may need to know the format version.
+set(CMAKE_IMPORT_FILE_VERSION 1)
+
+# Protect against multiple inclusion, which would fail when already imported targets are added once more.
+set(_targetsDefined)
+set(_targetsNotDefined)
+set(_expectedTargets)
+foreach(_expectedTarget QGpgme KF5::QGpgme)
+ list(APPEND _expectedTargets ${_expectedTarget})
+ if(NOT TARGET ${_expectedTarget})
+ list(APPEND _targetsNotDefined ${_expectedTarget})
+ endif()
+ if(TARGET ${_expectedTarget})
+ list(APPEND _targetsDefined ${_expectedTarget})
+ endif()
+endforeach()
+if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
+ set(CMAKE_IMPORT_FILE_VERSION)
+ cmake_policy(POP)
+ return()
+endif()
+if(NOT "${_targetsDefined}" STREQUAL "")
+ message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
+endif()
+unset(_targetsDefined)
+unset(_targetsNotDefined)
+unset(_expectedTargets)
+
+# Compute the installation prefix relative to this file.
+get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
+
+# Create imported target QGpgme
+add_library(QGpgme SHARED IMPORTED)
+
+set_target_properties(QGpgme PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include;${_IMPORT_PREFIX}/include/qgpgme"
+ INTERFACE_LINK_LIBRARIES "Gpgmepp;Qt5::Core"
+ IMPORTED_LOCATION "@resolved_libdir@/libqgpgme@libsuffix@"
+)
+
+if(CMAKE_VERSION VERSION_LESS 2.8.12)
+ message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
+endif()
+
+# Cleanup temporary variables.
+set(_IMPORT_PREFIX)
+
+# Loop over all imported files and verify that they actually exist
+foreach(target ${_IMPORT_CHECK_TARGETS} )
+ foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
+ if(NOT EXISTS "${file}" )
+ message(FATAL_ERROR "The imported target \"${target}\" references the file
+ \"${file}\"
+but this file does not exist. Possible reasons include:
+* The file was deleted, renamed, or moved to another location.
+* An install or uninstall procedure did not complete successfully.
+* The installation package was faulty and contained
+ \"${CMAKE_CURRENT_LIST_FILE}\"
+but not all the files it references.
+")
+ endif()
+ endforeach()
+ unset(_IMPORT_CHECK_FILES_FOR_${target})
+endforeach()
+unset(_IMPORT_CHECK_TARGETS)
+
+# This file does not depend on other imported targets which have
+# been exported from the same project but in a separate export set.
+
+# Commands beyond this point should not need to know the version.
+set(CMAKE_IMPORT_FILE_VERSION)
+cmake_policy(POP)
diff --git a/lang/qt/src/QGpgmeConfigVersion.cmake.in b/lang/qt/src/QGpgmeConfigVersion.cmake.in
new file mode 100644
index 0000000..04a12cb
--- /dev/null
+++ b/lang/qt/src/QGpgmeConfigVersion.cmake.in
@@ -0,0 +1,31 @@
+# CMake Version file for QGPGME.
+# Copyright (C) 2016 Intevation GmbH
+#
+# This file is part of GPGME.
+#
+# GPGME-CL is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GPGME-CL 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 General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA
+
+# based on a generated file from cmake.
+set(PACKAGE_VERSION "@LIBQGPGME_LT_CURRENT@.@LIBQGPGME_LT_AGE@.@LIBQGPGME_LT_REVISION@.@BUILD_REVISION@")
+
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/lang/qt/src/RefreshKeysJob b/lang/qt/src/RefreshKeysJob
new file mode 100644
index 0000000..678d8d0
--- /dev/null
+++ b/lang/qt/src/RefreshKeysJob
@@ -0,0 +1 @@
+#include "qgpgme/refreshkeysjob.h"
diff --git a/lang/qt/src/SignEncryptJob b/lang/qt/src/SignEncryptJob
new file mode 100644
index 0000000..4075e49
--- /dev/null
+++ b/lang/qt/src/SignEncryptJob
@@ -0,0 +1 @@
+#include "qgpgme/signencryptjob.h"
diff --git a/lang/qt/src/SignJob b/lang/qt/src/SignJob
new file mode 100644
index 0000000..135cab1
--- /dev/null
+++ b/lang/qt/src/SignJob
@@ -0,0 +1 @@
+#include "qgpgme/signjob.h"
diff --git a/lang/qt/src/SignKeyJob b/lang/qt/src/SignKeyJob
new file mode 100644
index 0000000..094753c
--- /dev/null
+++ b/lang/qt/src/SignKeyJob
@@ -0,0 +1 @@
+#include "qgpgme/signkeyjob.h"
diff --git a/lang/qt/src/TofuPolicyJob b/lang/qt/src/TofuPolicyJob
new file mode 100644
index 0000000..e379942
--- /dev/null
+++ b/lang/qt/src/TofuPolicyJob
@@ -0,0 +1 @@
+#include "qgpgme/tofupolicyjob.h"
diff --git a/lang/qt/src/VerifyDetachedJob b/lang/qt/src/VerifyDetachedJob
new file mode 100644
index 0000000..445fe27
--- /dev/null
+++ b/lang/qt/src/VerifyDetachedJob
@@ -0,0 +1 @@
+#include "qgpgme/verifydetachedjob.h"
diff --git a/lang/qt/src/VerifyOpaqueJob b/lang/qt/src/VerifyOpaqueJob
new file mode 100644
index 0000000..5292a70
--- /dev/null
+++ b/lang/qt/src/VerifyOpaqueJob
@@ -0,0 +1 @@
+#include "qgpgme/verifyopaquejob.h"
diff --git a/lang/qt/src/WKSPublishJob b/lang/qt/src/WKSPublishJob
new file mode 100644
index 0000000..747f7c8
--- /dev/null
+++ b/lang/qt/src/WKSPublishJob
@@ -0,0 +1 @@
+#include "qgpgme/wkspublishjob.h"
diff --git a/lang/qt/src/abstractimportjob.h b/lang/qt/src/abstractimportjob.h
new file mode 100644
index 0000000..572f203
--- /dev/null
+++ b/lang/qt/src/abstractimportjob.h
@@ -0,0 +1,64 @@
+/*
+ abstractimportjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2009 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_ABSTRACTIMPORTJOB_H__
+#define __KLEO_ABSTRACTIMPORTJOB_H__
+
+#include "job.h"
+
+#include "qgpgme_export.h"
+
+namespace GpgME
+{
+class Error;
+class ImportResult;
+}
+
+namespace QGpgME
+{
+
+class QGPGME_EXPORT AbstractImportJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit AbstractImportJob(QObject *parent);
+public:
+ ~AbstractImportJob();
+
+Q_SIGNALS:
+ void result(const GpgME::ImportResult &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_IMPORTJOB_H__
diff --git a/lang/qt/src/adduseridjob.h b/lang/qt/src/adduseridjob.h
new file mode 100644
index 0000000..1b5676f
--- /dev/null
+++ b/lang/qt/src/adduseridjob.h
@@ -0,0 +1,84 @@
+/*
+ adduseridjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_ADDUSERIDJOB_H__
+#define __KLEO_ADDUSERIDJOB_H__
+
+#include "job.h"
+
+#include <QtCore/QString>
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class to asynchronously add UIDs to OpenPGP keys
+
+ To use a AddUserIDJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the job with a call
+ to start(). This call might fail, in which case the AddUserIDJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the AddUserIDJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT AddUserIDJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit AddUserIDJob(QObject *parent);
+public:
+ ~AddUserIDJob();
+
+ /**
+ Starts the operation. \a key is the key to add the UID to. \a
+ name, \a email and \a comment are the components of the user id.
+ */
+ virtual GpgME::Error start(const GpgME::Key &key, const QString &name,
+ const QString &email, const QString &comment = QString()) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_ADDUSERIDJOB_H__
diff --git a/lang/qt/src/changeexpiryjob.h b/lang/qt/src/changeexpiryjob.h
new file mode 100644
index 0000000..7902cb8
--- /dev/null
+++ b/lang/qt/src/changeexpiryjob.h
@@ -0,0 +1,84 @@
+/*
+ changeexpiryjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_CHANGEEXPIRYJOB_H__
+#define __KLEO_CHANGEEXPIRYJOB_H__
+
+#include "job.h"
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+class QDateTime;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class to change expiry asynchronously
+
+ To use a ChangeExpiryJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the job with a call
+ to start(). This call might fail, in which case the ChangeExpiryJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ChangeExpiryJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ChangeExpiryJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit ChangeExpiryJob(QObject *parent);
+public:
+ ~ChangeExpiryJob();
+
+ /**
+ Starts the change-expiry operation. \a key is the key to change
+ the expiry of. \a expiry is the new expiry time. If \a expiry
+ is not valid, \a key is set to never expire.
+ */
+ virtual GpgME::Error start(const GpgME::Key &key, const QDateTime &expiry) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_CHANGEEXPIRYJOB_H__
diff --git a/lang/qt/src/changeownertrustjob.h b/lang/qt/src/changeownertrustjob.h
new file mode 100644
index 0000000..75c1163
--- /dev/null
+++ b/lang/qt/src/changeownertrustjob.h
@@ -0,0 +1,81 @@
+/*
+ changeownertrustjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_CHANGEOWNERTRUST_H__
+#define __KLEO_CHANGEOWNERTRUST_H__
+
+#include "job.h"
+
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+# include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class to change owner trust asynchronously
+
+ To use a ChangeOwnerTrustJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the job with a call
+ to start(). This call might fail, in which case the ChangeOwnerTrustJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ChangeOwnerTrustJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ChangeOwnerTrustJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit ChangeOwnerTrustJob(QObject *parent);
+public:
+ ~ChangeOwnerTrustJob();
+
+ /**
+ Starts the change-owner trust operation. \a key is the key to change
+ the owner trust of . \a trust is the new trust level.
+ */
+ virtual GpgME::Error start(const GpgME::Key &key, GpgME::Key::OwnerTrust trust) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_CHANGEOWNERTRUSTJOB_H__
diff --git a/lang/qt/src/changepasswdjob.h b/lang/qt/src/changepasswdjob.h
new file mode 100644
index 0000000..7290898
--- /dev/null
+++ b/lang/qt/src/changepasswdjob.h
@@ -0,0 +1,82 @@
+/*
+ changepasswdjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_CHANGEPASSWDJOB_H__
+#define __KLEO_CHANGEPASSWDJOB_H__
+
+#include "job.h"
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class to change a key's passphrase asynchronously
+
+ To use a ChangePasswdJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the job with a call
+ to start(). This call might fail, in which case the ChangePasswdJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ChangePasswdJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ChangePasswdJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit ChangePasswdJob(QObject *parent);
+public:
+ ~ChangePasswdJob();
+
+ /**
+ Starts the passphrase-change operation. \a key is the key to
+ change the passphrase of. The passphrase is queried by the
+ backend directly, you cannot give it to the job beforehand.
+ */
+ virtual GpgME::Error start(const GpgME::Key &key) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_CHANGEPASSWDJOB_H__
diff --git a/lang/qt/src/cryptoconfig.h b/lang/qt/src/cryptoconfig.h
new file mode 100644
index 0000000..c3f0c7e
--- /dev/null
+++ b/lang/qt/src/cryptoconfig.h
@@ -0,0 +1,400 @@
+/*
+ cryptoconfig.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef CRYPTOCONFIG_H
+#define CRYPTOCONFIG_H
+
+#include "qgpgme_export.h"
+#ifdef __cplusplus
+/* we read this file from a C compiler, and are only interested in the
+ * enums... */
+
+#include <QUrl>
+
+#include <vector>
+
+/* Start reading this file from the bottom up :) */
+
+namespace QGpgME
+{
+
+/**
+ * Description of a single option
+ */
+class QGPGME_EXPORT CryptoConfigEntry
+{
+
+public:
+#endif /* __cplusplus */
+ /**
+ @li basic This option should always be offered to the user.
+ @li advanced This option may be offered to advanced users.
+ @li expert This option should only be offered to expert users.
+ */
+ enum Level { Level_Basic = 0,
+ Level_Advanced = 1,
+ Level_Expert = 2
+ };
+
+ /**
+ Type of the argument
+ @li ArgType_None The option is set or not set, but no argument.
+ @li ArgType_String An unformatted string.
+ @li ArgType_Int A signed integer number.
+ @li ArgType_UInt An unsigned integer number.
+ @li ArgType_Path A string that describes the pathname of a file.
+ The file does not necessarily need to exist.
+ Separated from string so that e.g. a FileDialog can be used.
+ @li ArgType_DirPath A string that describes the pathname of a directory.
+ The directory does not necessarily need to exist.
+ Separated from path so that e.g. a FileDialog can be used which only
+ allows directories to be selected.
+ @li ArgType_LDAPURL A LDAP URL
+ Separated from URL so that a more specific widget can be shown, hiding the url syntax
+ */
+ enum ArgType { ArgType_None = 0,
+ ArgType_String = 1,
+ ArgType_Int = 2,
+ ArgType_UInt = 3,
+ ArgType_Path = 4,
+ /* Nr. 5 was URL historically. */
+ ArgType_LDAPURL = 6,
+ ArgType_DirPath = 7,
+
+ NumArgType
+ };
+
+#ifdef __cplusplus
+ virtual ~CryptoConfigEntry() {}
+
+ /**
+ * Return the internal name of this entry
+ */
+ virtual QString name() const = 0;
+
+ /**
+ * @return user-visible description of this entry
+ */
+ virtual QString description() const = 0;
+
+ /**
+ * @return "component/group/name"
+ */
+ virtual QString path() const = 0;
+
+ /**
+ * @return true if the argument is optional
+ */
+ virtual bool isOptional() const = 0;
+
+ /**
+ * @return true if the entry is readonly
+ */
+ virtual bool isReadOnly() const = 0;
+
+ /**
+ * @return true if the argument can be given multiple times
+ */
+ virtual bool isList() const = 0;
+
+ /**
+ * @return true if the argument can be changed at runtime
+ */
+ virtual bool isRuntime() const = 0;
+
+ /**
+ * User level
+ */
+ virtual Level level() const = 0;
+
+ /**
+ * Argument type
+ */
+ virtual ArgType argType() const = 0;
+
+ /**
+ * Return true if the option is set, i.e. different from default
+ */
+ virtual bool isSet() const = 0;
+
+ /**
+ * Return value as a bool (only allowed for ArgType_None)
+ */
+ virtual bool boolValue() const = 0;
+
+ /**
+ * Return value as a string (available for all argtypes)
+ * The returned string can be empty (explicitly set to empty) or null (not set).
+ */
+ virtual QString stringValue() const = 0;
+
+ /**
+ * Return value as a signed int
+ */
+ virtual int intValue() const = 0;
+
+ /**
+ * Return value as an unsigned int
+ */
+ virtual unsigned int uintValue() const = 0;
+
+ /**
+ * Return value as a URL (only meaningful for Path and URL argtypes)
+ */
+ virtual QUrl urlValue() const = 0;
+
+ /**
+ * Return number of times the option is set (only valid for ArgType_None, if isList())
+ */
+ virtual unsigned int numberOfTimesSet() const = 0;
+
+ /**
+ * Return value as a list of signed ints
+ */
+ virtual std::vector<int> intValueList() const = 0;
+
+ /**
+ * Return value as a list of unsigned ints
+ */
+ virtual std::vector<unsigned int> uintValueList() const = 0;
+
+ /**
+ * Return value as a list of URLs (only meaningful for Path and URL argtypes, if isList())
+ */
+ virtual QList<QUrl> urlValueList() const = 0;
+
+ /**
+ * Reset an option to its default value
+ */
+ virtual void resetToDefault() = 0;
+
+ /**
+ * Define whether the option is set or not (only allowed for ArgType_None)
+ * #### TODO: and for options with optional args
+ */
+ virtual void setBoolValue(bool) = 0;
+
+ /**
+ * Set string value (allowed for all argtypes)
+ */
+ virtual void setStringValue(const QString &) = 0;
+
+ /**
+ * Set a new signed int value
+ */
+ virtual void setIntValue(int) = 0;
+
+ /**
+ * Set a new unsigned int value
+ */
+ virtual void setUIntValue(unsigned int) = 0;
+
+ /**
+ * Set value as a URL (only meaningful for Path (if local) and URL argtypes)
+ */
+ virtual void setURLValue(const QUrl &) = 0;
+
+ /**
+ * Set the number of times the option is set (only valid for ArgType_None, if isList())
+ */
+ virtual void setNumberOfTimesSet(unsigned int) = 0;
+
+ /**
+ * Set a new list of signed int values
+ */
+ virtual void setIntValueList(const std::vector<int> &) = 0;
+
+ /**
+ * Set a new list of unsigned int values
+ */
+ virtual void setUIntValueList(const std::vector<unsigned int> &) = 0;
+
+ /**
+ * Set value as a URL list (only meaningful for Path (if all URLs are local) and URL argtypes, if isList())
+ */
+ virtual void setURLValueList(const QList<QUrl> &) = 0;
+
+ /**
+ * @return true if the value was changed
+ */
+ virtual bool isDirty() const = 0;
+};
+
+/**
+ * Group containing a set of config options
+ */
+class QGPGME_EXPORT CryptoConfigGroup
+{
+
+public:
+ virtual ~CryptoConfigGroup() {}
+
+ /**
+ * Return the internal name of this group
+ */
+ virtual QString name() const = 0;
+
+ /**
+ * Return the name of the icon for this group
+ */
+ virtual QString iconName() const = 0;
+
+ /**
+ * @return user-visible description of this group
+ */
+ virtual QString description() const = 0;
+
+ /**
+ * @return "component/group"
+ */
+ virtual QString path() const = 0;
+
+ /**
+ * User level
+ */
+ virtual CryptoConfigEntry::Level level() const = 0;
+
+ /**
+ * Returns the list of entries that are known by this group.
+ *
+ * @return list of group entry names.
+ **/
+ virtual QStringList entryList() const = 0;
+
+ /**
+ * @return the configuration object for a given entry in this group
+ * The object is owned by CryptoConfigGroup, don't delete it.
+ * Groups cannot be nested, so all entries returned here are pure entries, no groups.
+ */
+ virtual CryptoConfigEntry *entry(const QString &name) const = 0;
+};
+
+/**
+ * Crypto config for one component (e.g. gpg-agent, dirmngr etc.)
+ */
+class QGPGME_EXPORT CryptoConfigComponent
+{
+
+public:
+ virtual ~CryptoConfigComponent() {}
+
+ /**
+ * Return the internal name of this component
+ */
+ virtual QString name() const = 0;
+
+ /**
+ * Return the name of the icon for this component
+ */
+ virtual QString iconName() const = 0;
+
+ /**
+ * Return user-visible description of this component
+ */
+ virtual QString description() const = 0;
+
+ /**
+ * Returns the list of groups that are known about.
+ *
+ * @return list of group names. One of them can be "<nogroup>", which is the group where all
+ * "toplevel" options (belonging to no group) are.
+ */
+ virtual QStringList groupList() const = 0;
+
+ /**
+ * @return the configuration object for a given group
+ * The object is owned by CryptoConfigComponent, don't delete it.
+ */
+ virtual CryptoConfigGroup *group(const QString &name) const = 0;
+
+};
+
+/**
+ * Main interface to crypto configuration.
+ */
+class QGPGME_EXPORT CryptoConfig
+{
+
+public:
+ virtual ~CryptoConfig() {}
+
+ /**
+ * Returns the list of known components (e.g. "gpg-agent", "dirmngr" etc.).
+ * Use @ref component() to retrieve more information about each one.
+ * @return list of component names.
+ **/
+ virtual QStringList componentList() const = 0;
+
+ /**
+ * @return the configuration object for a given component
+ * The object is owned by CryptoConfig, don't delete it.
+ */
+ virtual CryptoConfigComponent *component(const QString &name) const = 0;
+
+ /**
+ * Convenience method to get hold of a single configuration entry when
+ * its component, group and name are known. This can be used to read
+ * the value and/or to set a value to it.
+ *
+ * @return the configuration object for a single configuration entry, 0 if not found.
+ * The object is owned by CryptoConfig, don't delete it.
+ */
+ CryptoConfigEntry *entry(const QString &componentName, const QString &groupName, const QString &entryName) const
+ {
+ const QGpgME::CryptoConfigComponent *comp = component(componentName);
+ const QGpgME::CryptoConfigGroup *group = comp ? comp->group(groupName) : 0;
+ return group ? group->entry(entryName) : 0;
+ }
+
+ /**
+ * Write back changes
+ *
+ * @param runtime If this option is set, the changes will take effect at run-time, as
+ * far as this is possible. Otherwise, they will take effect at the next
+ * start of the respective backend programs.
+ */
+ virtual void sync(bool runtime) = 0;
+
+ /**
+ * Tells the CryptoConfig to discard any cached information, including
+ * all components, groups and entries.
+ * Call this to free some memory when you won't be using the object
+ * for some time.
+ * DON'T call this if you're holding pointers to components, groups or entries.
+ */
+ virtual void clear() = 0;
+};
+
+}
+#endif /* __cplusplus */
+#endif /* CRYPTOCONFIG_H */
diff --git a/lang/qt/src/dataprovider.cpp b/lang/qt/src/dataprovider.cpp
new file mode 100644
index 0000000..533b67d
--- /dev/null
+++ b/lang/qt/src/dataprovider.cpp
@@ -0,0 +1,282 @@
+/* dataprovider.cpp
+ Copyright (C) 2004 Klar�vdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ This file is part of QGPGME.
+
+ QGPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ QGPGME is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with QGPGME; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+// -*- c++ -*-
+
+#include <dataprovider.h>
+
+#include <error.h>
+
+#include <QIODevice>
+#include <QProcess>
+
+#include <cstdio>
+#include <cstring>
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+//
+//
+// QByteArrayDataProvider
+//
+//
+
+static bool resizeAndInit(QByteArray &ba, size_t newSize)
+{
+ const size_t oldSize = ba.size();
+ ba.resize(newSize);
+ const bool ok = (newSize == static_cast<size_t>(ba.size()));
+ if (ok) {
+ memset(ba.data() + oldSize, 0, newSize - oldSize);
+ }
+ return ok;
+}
+
+QByteArrayDataProvider::QByteArrayDataProvider()
+ : GpgME::DataProvider(), mOff(0) {}
+
+QByteArrayDataProvider::QByteArrayDataProvider(const QByteArray &initialData)
+ : GpgME::DataProvider(), mArray(initialData), mOff(0) {}
+
+QByteArrayDataProvider::~QByteArrayDataProvider() {}
+
+ssize_t QByteArrayDataProvider::read(void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::read( %p, %d )", buffer, bufSize );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ if (mOff >= mArray.size()) {
+ return 0; // EOF
+ }
+ size_t amount = qMin(bufSize, static_cast<size_t>(mArray.size() - mOff));
+ assert(amount > 0);
+ memcpy(buffer, mArray.data() + mOff, amount);
+ mOff += amount;
+ return amount;
+}
+
+ssize_t QByteArrayDataProvider::write(const void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ if (mOff >= mArray.size()) {
+ resizeAndInit(mArray, mOff + bufSize);
+ }
+ if (mOff >= mArray.size()) {
+ Error::setSystemError(GPG_ERR_EIO);
+ return -1;
+ }
+ assert(bufSize <= static_cast<size_t>(mArray.size()) - mOff);
+ memcpy(mArray.data() + mOff, buffer, bufSize);
+ mOff += bufSize;
+ return bufSize;
+}
+
+off_t QByteArrayDataProvider::seek(off_t offset, int whence)
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::seek( %d, %d )", int(offset), whence );
+#endif
+ int newOffset = mOff;
+ switch (whence) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset += offset;
+ break;
+ case SEEK_END:
+ newOffset = mArray.size() + offset;
+ break;
+ default:
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ return mOff = newOffset;
+}
+
+void QByteArrayDataProvider::release()
+{
+#ifndef NDEBUG
+ //qDebug( "QByteArrayDataProvider::release()" );
+#endif
+ mArray = QByteArray();
+}
+
+//
+//
+// QIODeviceDataProvider
+//
+//
+
+QIODeviceDataProvider::QIODeviceDataProvider(const std::shared_ptr<QIODevice> &io)
+ : GpgME::DataProvider(),
+ mIO(io),
+ mErrorOccurred(false),
+ mHaveQProcess(qobject_cast<QProcess *>(io.get()))
+{
+ assert(mIO);
+}
+
+QIODeviceDataProvider::~QIODeviceDataProvider() {}
+
+bool QIODeviceDataProvider::isSupported(Operation op) const
+{
+ const QProcess *const proc = qobject_cast<QProcess *>(mIO.get());
+ bool canRead = true;
+ if (proc) {
+ canRead = proc->readChannel() == QProcess::StandardOutput;
+ }
+
+ switch (op) {
+ case Read: return mIO->isReadable() && canRead;
+ case Write: return mIO->isWritable();
+ case Seek: return !mIO->isSequential();
+ case Release: return true;
+ default: return false;
+ }
+}
+
+static qint64 blocking_read(const std::shared_ptr<QIODevice> &io, char *buffer, qint64 maxSize)
+{
+ while (!io->bytesAvailable()) {
+ if (!io->waitForReadyRead(-1)) {
+ if (const QProcess *const p = qobject_cast<QProcess *>(io.get())) {
+ if (p->error() == QProcess::UnknownError &&
+ p->exitStatus() == QProcess::NormalExit &&
+ p->exitCode() == 0) {
+ return 0;
+ } else {
+ Error::setSystemError(GPG_ERR_EIO);
+ return -1;
+ }
+ } else {
+ return 0; // assume EOF (loses error cases :/ )
+ }
+ }
+ }
+ return io->read(buffer, maxSize);
+}
+
+ssize_t QIODeviceDataProvider::read(void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::read( %p, %lu )", buffer, bufSize );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+ const qint64 numRead = mHaveQProcess
+ ? blocking_read(mIO, static_cast<char *>(buffer), bufSize)
+ : mIO->read(static_cast<char *>(buffer), bufSize);
+
+ //workaround: some QIODevices (known example: QProcess) might not return 0 (EOF), but immediately -1 when finished. If no
+ //errno is set, gpgme doesn't detect the error and loops forever. So return 0 on the very first -1 in case errno is 0
+
+ ssize_t rc = numRead;
+ if (numRead < 0 && !Error::hasSystemError()) {
+ if (mErrorOccurred) {
+ Error::setSystemError(GPG_ERR_EIO);
+ } else {
+ rc = 0;
+ }
+ }
+ if (numRead < 0) {
+ mErrorOccurred = true;
+ }
+ return rc;
+}
+
+ssize_t QIODeviceDataProvider::write(const void *buffer, size_t bufSize)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::write( %p, %lu )", buffer, static_cast<unsigned long>( bufSize ) );
+#endif
+ if (bufSize == 0) {
+ return 0;
+ }
+ if (!buffer) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return -1;
+ }
+
+ return mIO->write(static_cast<const char *>(buffer), bufSize);
+}
+
+off_t QIODeviceDataProvider::seek(off_t offset, int whence)
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::seek( %d, %d )", int(offset), whence );
+#endif
+ if (mIO->isSequential()) {
+ Error::setSystemError(GPG_ERR_ESPIPE);
+ return (off_t) - 1;
+ }
+ qint64 newOffset = mIO->pos();
+ switch (whence) {
+ case SEEK_SET:
+ newOffset = offset;
+ break;
+ case SEEK_CUR:
+ newOffset += offset;
+ break;
+ case SEEK_END:
+ newOffset = mIO->size() + offset;
+ break;
+ default:
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ if (!mIO->seek(newOffset)) {
+ Error::setSystemError(GPG_ERR_EINVAL);
+ return (off_t) - 1;
+ }
+ return newOffset;
+}
+
+void QIODeviceDataProvider::release()
+{
+#ifndef NDEBUG
+ //qDebug( "QIODeviceDataProvider::release()" );
+#endif
+ mIO->close();
+}
diff --git a/lang/qt/src/dataprovider.h b/lang/qt/src/dataprovider.h
new file mode 100644
index 0000000..337f264
--- /dev/null
+++ b/lang/qt/src/dataprovider.h
@@ -0,0 +1,95 @@
+/* dataprovider.h
+ Copyright (C) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ This file is part of QGPGME.
+
+ QGPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published
+ by the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ QGPGME is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with QGPGME; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+// -*- c++ -*-
+#ifndef __QGPGME_DATAPROVIDER_H__
+#define __QGPGME_DATAPROVIDER_H__
+
+#include "qgpgme_export.h"
+#include <interfaces/dataprovider.h>
+#include <memory>
+
+#include <QtCore/QByteArray>
+
+
+class QIODevice;
+
+namespace QGpgME
+{
+
+class QGPGME_EXPORT QByteArrayDataProvider : public GpgME::DataProvider
+{
+public:
+ QByteArrayDataProvider();
+ explicit QByteArrayDataProvider(const QByteArray &initialData);
+ ~QByteArrayDataProvider();
+
+ const QByteArray &data() const
+ {
+ return mArray;
+ }
+
+private:
+ // these shall only be accessed through the dataprovider
+ // interface, where they're public:
+ bool isSupported(Operation) const
+ {
+ return true;
+ }
+ ssize_t read(void *buffer, size_t bufSize);
+ ssize_t write(const void *buffer, size_t bufSize);
+ off_t seek(off_t offset, int whence);
+ void release();
+
+private:
+ QByteArray mArray;
+ off_t mOff;
+};
+
+class QGPGME_EXPORT QIODeviceDataProvider : public GpgME::DataProvider
+{
+public:
+ explicit QIODeviceDataProvider(const std::shared_ptr<QIODevice> &initialData);
+ ~QIODeviceDataProvider();
+
+ const std::shared_ptr<QIODevice> &ioDevice() const
+ {
+ return mIO;
+ }
+
+private:
+ // these shall only be accessed through the dataprovider
+ // interface, where they're public:
+ bool isSupported(Operation) const;
+ ssize_t read(void *buffer, size_t bufSize);
+ ssize_t write(const void *buffer, size_t bufSize);
+ off_t seek(off_t offset, int whence);
+ void release();
+
+private:
+ const std::shared_ptr<QIODevice> mIO;
+ bool mErrorOccurred : 1;
+ bool mHaveQProcess : 1;
+};
+
+} // namespace QGpgME
+
+#endif
diff --git a/lang/qt/src/decryptjob.h b/lang/qt/src/decryptjob.h
new file mode 100644
index 0000000..c4fc86f
--- /dev/null
+++ b/lang/qt/src/decryptjob.h
@@ -0,0 +1,100 @@
+/*
+ decryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_DECRYPTJOB_H__
+#define __KLEO_DECRYPTJOB_H__
+
+#include "job.h"
+
+#include <memory>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class DecryptionResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous decrypters
+
+ To use a DecryptJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the decryption with a
+ call to start(). This call might fail, in which case the
+ DecryptJob instance will have scheduled it's own destruction with
+ a call to QObject::deleteLater().
+
+ After result() is emitted, the DecryptJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT DecryptJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit DecryptJob(QObject *parent);
+public:
+ ~DecryptJob();
+
+ /**
+ Starts the decryption operation. \a cipherText is the data to
+ decrypt.
+ */
+ virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &cipherText) = 0;
+
+ /*!
+ \overload
+
+ If \a plainText is non-null, the plaintext is written
+ there. Otherwise, it will be delivered in the second argument
+ of result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText = std::shared_ptr<QIODevice>()) = 0;
+
+ virtual GpgME::DecryptionResult exec(const QByteArray &cipherText,
+ QByteArray &plainText) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::DecryptionResult &result, const QByteArray &plainText, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_DECRYPTJOB_H__
diff --git a/lang/qt/src/decryptverifyjob.h b/lang/qt/src/decryptverifyjob.h
new file mode 100644
index 0000000..97af008
--- /dev/null
+++ b/lang/qt/src/decryptverifyjob.h
@@ -0,0 +1,105 @@
+/*
+ decryptverifyjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_DECRYPTVERIFYJOB_H__
+#define __KLEO_DECRYPTVERIFYJOB_H__
+
+#include "job.h"
+
+#include <memory>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class DecryptionResult;
+class VerificationResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous combined decrypters and verifiers
+
+ To use a DecryptVerifyJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the operation with a
+ call to start(). This call might fail, in which case the
+ DecryptVerifyJob instance will have scheduled it's own destruction with
+ a call to QObject::deleteLater().
+
+ After result() is emitted, the DecryptVerifyJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT DecryptVerifyJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit DecryptVerifyJob(QObject *parent);
+public:
+ ~DecryptVerifyJob();
+
+ /**
+ 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;
+
+ /*!
+ \overload
+
+ If \a plainText is non-null, the plaintext is written
+ there. Otherwise, it will be delivered in the third argument
+ of result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText = std::shared_ptr<QIODevice>()) = 0;
+
+ /** Synchronous equivalent of start() */
+ virtual std::pair<GpgME::DecryptionResult, GpgME::VerificationResult>
+ exec(const QByteArray &cipherText, QByteArray &plainText) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::DecryptionResult &decryptionresult,
+ const GpgME::VerificationResult &verificationresult,
+ const QByteArray &plainText, const QString &auditLogAsHtml = QString(),
+ const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_DECRYPTVERIFYJOB_H__
diff --git a/lang/qt/src/defaultkeygenerationjob.cpp b/lang/qt/src/defaultkeygenerationjob.cpp
new file mode 100644
index 0000000..8257a72
--- /dev/null
+++ b/lang/qt/src/defaultkeygenerationjob.cpp
@@ -0,0 +1,125 @@
+/* defaultkeygenerationjob.cpp
+
+ Copyright (c) 2016 Klarälvdalens Datakonsult AB
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "defaultkeygenerationjob.h"
+#include "protocol.h"
+#include "keygenerationjob.h"
+
+#include <QPointer>
+#include <QEvent>
+
+using namespace QGpgME;
+
+namespace QGpgME {
+
+class DefaultKeyGenerationJob::Private
+{
+public:
+ Private()
+ {}
+
+ ~Private()
+ {
+ if (job) {
+ job->deleteLater();
+ }
+ }
+
+ QPointer<KeyGenerationJob> job;
+};
+}
+
+
+DefaultKeyGenerationJob::DefaultKeyGenerationJob(QObject* parent)
+ : Job(parent)
+ , d(new DefaultKeyGenerationJob::Private())
+{
+}
+
+DefaultKeyGenerationJob::~DefaultKeyGenerationJob()
+{
+ delete d;
+}
+
+QString DefaultKeyGenerationJob::auditLogAsHtml() const
+{
+ return d->job ? d->job->auditLogAsHtml() : QString();
+}
+
+GpgME::Error DefaultKeyGenerationJob::auditLogError() const
+{
+ return d->job ? d->job->auditLogError() : GpgME::Error();
+}
+
+void DefaultKeyGenerationJob::slotCancel()
+{
+ if (d->job) {
+ d->job->slotCancel();
+ }
+}
+
+GpgME::Error DefaultKeyGenerationJob::start(const QString &email, const QString &name)
+{
+ const QString args = QStringLiteral("<GnupgKeyParms format=\"internal\">\n"
+ "%ask-passphrase\n"
+ "key-type: RSA\n"
+ "key-length: 2048\n"
+ "key-usage: sign\n"
+ "subkey-type: RSA\n"
+ "subkey-length: 2048\n"
+ "subkey-usage: encrypt\n"
+ "name-email: %1\n"
+ "name-real: %2\n"
+ "</GnupgKeyParms>").arg(email, name);
+
+ d->job = openpgp()->keyGenerationJob();
+ d->job->installEventFilter(this);
+ connect(d->job, &KeyGenerationJob::result,
+ this, &DefaultKeyGenerationJob::result);
+ connect(d->job, &KeyGenerationJob::done,
+ this, &DefaultKeyGenerationJob::done);
+ connect(d->job, &KeyGenerationJob::done,
+ this, &QObject::deleteLater);
+ return d->job->start(args);
+}
+
+bool DefaultKeyGenerationJob::eventFilter(QObject *watched, QEvent *event)
+{
+ // Intercept the KeyGenerationJob's deferred delete event. We want the job
+ // to live at least as long as we do so we can delegate calls to it. We will
+ // delete the job manually afterwards.
+ if (watched == d->job && event->type() == QEvent::DeferredDelete) {
+ return true;
+ }
+
+ return Job::eventFilter(watched, event);
+}
+
+#include "defaultkeygenerationjob.moc"
diff --git a/lang/qt/src/defaultkeygenerationjob.h b/lang/qt/src/defaultkeygenerationjob.h
new file mode 100644
index 0000000..5b7334c
--- /dev/null
+++ b/lang/qt/src/defaultkeygenerationjob.h
@@ -0,0 +1,76 @@
+/* defaultkeygenerationjob.h
+
+ Copyright (c) 2016 Klarälvdalens Datakonsult AB
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef QGPGME_DEFAULTKEYGENERATION_H
+#define QGPGME_DEFAULTKEYGENERATION_H
+
+#include "job.h"
+
+#include "qgpgme_export.h"
+
+namespace GpgME {
+class KeyGenerationResult;
+}
+
+namespace QGpgME{
+
+/**
+ * Generates a PGP RSA/2048 bit key pair for given name and email address.
+ */
+class QGPGME_EXPORT DefaultKeyGenerationJob : public Job
+{
+ Q_OBJECT
+public:
+ explicit DefaultKeyGenerationJob(QObject *parent = Q_NULLPTR);
+ ~DefaultKeyGenerationJob();
+
+ GpgME::Error start(const QString &email, const QString &name);
+
+ QString auditLogAsHtml() const Q_DECL_OVERRIDE;
+ GpgME::Error auditLogError() const Q_DECL_OVERRIDE;
+
+
+public Q_SLOTS:
+ void slotCancel() Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void result(const GpgME::KeyGenerationResult &result, const QByteArray &pubkeyData,
+ const QString &auditLogAsHtml, const GpgME::Error &auditLogError);
+
+protected:
+ bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
+
+private:
+ class Private;
+ Private * const d;
+};
+
+}
+
+#endif
diff --git a/lang/qt/src/deletejob.h b/lang/qt/src/deletejob.h
new file mode 100644
index 0000000..f8479b1
--- /dev/null
+++ b/lang/qt/src/deletejob.h
@@ -0,0 +1,83 @@
+/*
+ deletejob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_DELETEJOB_H__
+#define __KLEO_DELETEJOB_H__
+
+#include "qgpgme_export.h"
+#include "job.h"
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous deleters
+
+ To use a DeleteJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the delete with a call
+ to start(). This call might fail, in which case the DeleteJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the DeleteJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT DeleteJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit DeleteJob(QObject *parent);
+public:
+ ~DeleteJob();
+
+ /**
+ Starts the delete operation. \a key represents the key to
+ delete, \a allowSecretKeyDeletion specifies if a key may also
+ be deleted if the secret key part is available, too.
+ */
+ virtual GpgME::Error start(const GpgME::Key &key, bool allowSecretKeyDeletion = false) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_DELETEJOB_H__
diff --git a/lang/qt/src/downloadjob.h b/lang/qt/src/downloadjob.h
new file mode 100644
index 0000000..09eecf6
--- /dev/null
+++ b/lang/qt/src/downloadjob.h
@@ -0,0 +1,103 @@
+/*
+ downloadjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_DOWNLOADJOB_H__
+#define __KLEO_DOWNLOADJOB_H__
+
+#include "job.h"
+
+#include <QtCore/QByteArray>
+
+#include <memory>
+
+namespace GpgME
+{
+class Error;
+}
+
+class QStringList;
+class QIODevice;
+class QByteArray;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous downloaders
+
+ To use a DownloadJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the download with a call
+ to start(). This call might fail, in which case the DownloadJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the DownloadJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT DownloadJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit DownloadJob(QObject *parent);
+public:
+ ~DownloadJob();
+
+ /**
+ Starts the download operation. \a fingerprint is the
+ fingerprint of the key to download. If \a fingerprint is empty,
+ contains only whitespace or anything other than a fingerprint,
+ the result is undefined.
+
+ Output is written to \a keyData, if given. Otherwise, it is
+ passed as the second argument of result().
+ */
+ virtual GpgME::Error start(const QByteArray &fingerprint,
+ const std::shared_ptr<QIODevice> &keyData) = 0;
+
+ /**
+ Starts the download operation. \a fingerprints is a list of
+ fingerprints used to specify the list of keys downloaded. Empty
+ patterns are ignored. If \a fingerprints is empty, contains
+ only empty strings or anything other than fingerprints, the
+ result is undefined.
+ */
+ virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QStringList &fingerprints) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QByteArray &keyData, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_DOWNLOADJOB_H__
diff --git a/lang/qt/src/encryptjob.h b/lang/qt/src/encryptjob.h
new file mode 100644
index 0000000..4ff9c82
--- /dev/null
+++ b/lang/qt/src/encryptjob.h
@@ -0,0 +1,136 @@
+/*
+ encryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_ENCRYPTJOB_H__
+#define __KLEO_ENCRYPTJOB_H__
+
+#include "job.h"
+
+#include <memory>
+#include <vector>
+
+#ifdef BUILDING_QGPGME
+# include "context.h"
+#else
+# include <gpgme++/context.h>
+#endif
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class Key;
+class EncryptionResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous encrypters
+
+ To use a EncryptJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the encryption with a
+ call to start(). This call might fail, in which case the
+ EncryptJob instance will have scheduled it's own destruction with
+ a call to QObject::deleteLater().
+
+ After result() is emitted, the EncryptJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT EncryptJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit EncryptJob(QObject *parent);
+public:
+ ~EncryptJob();
+
+ /**
+ Starts the encryption operation. \a recipients is the a list of
+ keys to encrypt \a plainText to. Empty (null) keys are
+ ignored. If \a recipients is empty, performs symmetric
+ (passphrase) encryption.
+
+ If \a alwaysTrust is true, validity checking for the keys will
+ not be performed, but full validity assumed for all keys
+ without further checks.
+ */
+ virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, bool alwaysTrust = false) = 0;
+
+ /*!
+ \overload
+
+ If \a cipherText is non-null, the ciphertext is written
+ there. Otherwise, it will be delivered in the second argument of
+ result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+ bool alwaysTrust = false) = 0;
+
+ virtual GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText,
+ bool alwaysTrust, QByteArray &cipherText) = 0;
+ /*!
+ This is a hack to request BASE64 output (instead of whatever
+ comes out normally).
+ */
+ virtual void setOutputIsBase64Encoded(bool) = 0;
+
+ /** Like start but with an additional argument for EncryptionFlags for
+ * more flexibility. */
+ virtual void start(const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+ const GpgME::Context::EncryptionFlags flags = GpgME::Context::None) = 0;
+
+ /** Like exec but with an additional argument for EncryptionFlags for
+ * more flexibility. */
+ virtual GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText,
+ const GpgME::Context::EncryptionFlags flags, QByteArray &cipherText) = 0;
+Q_SIGNALS:
+ void result(const GpgME::EncryptionResult &result, const QByteArray &cipherText, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_ENCRYPTJOB_H__
diff --git a/lang/qt/src/exportjob.h b/lang/qt/src/exportjob.h
new file mode 100644
index 0000000..583d4c0
--- /dev/null
+++ b/lang/qt/src/exportjob.h
@@ -0,0 +1,87 @@
+/*
+ exportjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_EXPORTJOB_H__
+#define __QGPGME_EXPORTJOB_H__
+
+#include "qgpgme_export.h"
+#include "job.h"
+
+#include <QtCore/QByteArray>
+
+namespace GpgME
+{
+class Error;
+}
+
+class QStringList;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous exporters
+
+ To use a ExportJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the export with a call
+ to start(). This call might fail, in which case the ExportJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ExportJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ExportJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit ExportJob(QObject *parent);
+public:
+ ~ExportJob();
+
+ /**
+ Starts the export operation. \a patterns is a list of patterns
+ used to restrict the list of keys exported. Empty patterns are
+ ignored. If \a patterns is empty or contains only empty
+ strings, all available keys are exported.
+ */
+ virtual GpgME::Error start(const QStringList &patterns) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QByteArray &keyData, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __QGPGME_EXPORTJOB_H__
diff --git a/lang/qt/src/gpgme_backend_debug.cpp b/lang/qt/src/gpgme_backend_debug.cpp
new file mode 100644
index 0000000..6dfb313
--- /dev/null
+++ b/lang/qt/src/gpgme_backend_debug.cpp
@@ -0,0 +1,10 @@
+// This file is autogenerated by CMake: DO NOT EDIT
+
+#include "gpgme_backend_debug.h"
+
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
+Q_LOGGING_CATEGORY(GPGPME_BACKEND_LOG, "log_gpgme_backend", QtWarningMsg)
+#else
+Q_LOGGING_CATEGORY(GPGPME_BACKEND_LOG, "log_gpgme_backend")
+#endif
diff --git a/lang/qt/src/gpgme_backend_debug.h b/lang/qt/src/gpgme_backend_debug.h
new file mode 100644
index 0000000..5ac93db
--- /dev/null
+++ b/lang/qt/src/gpgme_backend_debug.h
@@ -0,0 +1,11 @@
+// This file is autogenerated by CMake: DO NOT EDIT
+
+#ifndef GPGPME_BACKEND_LOG_H
+#define GPGPME_BACKEND_LOG_H
+
+#include <QLoggingCategory>
+
+Q_DECLARE_LOGGING_CATEGORY(GPGPME_BACKEND_LOG)
+
+
+#endif
diff --git a/lang/qt/src/hierarchicalkeylistjob.h b/lang/qt/src/hierarchicalkeylistjob.h
new file mode 100644
index 0000000..2ec187d
--- /dev/null
+++ b/lang/qt/src/hierarchicalkeylistjob.h
@@ -0,0 +1,125 @@
+/*
+ hierarchicalkeylistjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_HIERARCHICALKEYLISTJOB_H__
+#define __KLEO_HIERARCHICALKEYLISTJOB_H__
+
+#include "qgpgme_export.h"
+#include "keylistjob.h"
+#include "cryptobackend.h"
+
+#ifdef BUILDING_QGPGME
+# include "keylistresult.h"
+#else
+#include <gpgme++/keylistresult.h>
+#endif
+
+#include <QPointer>
+
+#include <set>
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+class KeyListJob;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short A convenience job that additionally fetches all available issuers.
+
+ To use a HierarchicalKeyListJob, pass it a CryptoBackend
+ implementation, connect the progress() and result() signals to
+ suitable slots and then start the keylisting with a call to
+ start(). This call might fail, in which case the
+ HierarchicalKeyListJob instance will have scheduled it's own
+ destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the HierarchicalKeyListJob will
+ schedule its own destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT HierarchicalKeyListJob : public KeyListJob
+{
+ Q_OBJECT
+public:
+ explicit HierarchicalKeyListJob(const Protocol *protocol,
+ bool remote = false, bool includeSigs = false,
+ bool validating = false);
+ ~HierarchicalKeyListJob();
+
+ /**
+ Starts the keylist operation. \a patterns is a list of patterns
+ used to restrict the list of keys returned. Empty patterns are
+ ignored. \a patterns must not be empty or contain only empty
+ patterns; use the normal KeyListJob for a full listing.
+
+ The \a secretOnly parameter is ignored by
+ HierarchicalKeyListJob and must be set to false.
+ */
+ GpgME::Error start(const QStringList &patterns, bool secretOnly = false) Q_DECL_OVERRIDE;
+
+ GpgME::KeyListResult exec(const QStringList &patterns, bool secretOnly,
+ std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void slotResult(const GpgME::KeyListResult &);
+ void slotNextKey(const GpgME::Key &key);
+ /* from Job */
+ void slotCancel() Q_DECL_OVERRIDE;
+
+private:
+ GpgME::Error startAJob();
+
+private:
+ const Protocol *const mProtocol;
+ const bool mRemote;
+ const bool mIncludeSigs;
+ const bool mValidating;
+ bool mTruncated;
+ std::set<QString> mSentSet; // keys already sent (prevent duplicates even if the backend should return them)
+ std::set<QString> mScheduledSet; // keys already scheduled (by starting a job for them)
+ std::set<QString> mNextSet; // keys to schedule for the next iteraton
+ GpgME::KeyListResult mIntermediateResult;
+ QPointer<KeyListJob> mJob;
+};
+
+}
+
+#endif // __KLEO_HIERARCHICALKEYLISTJOB_H__
diff --git a/lang/qt/src/importfromkeyserverjob.h b/lang/qt/src/importfromkeyserverjob.h
new file mode 100644
index 0000000..f548ea7
--- /dev/null
+++ b/lang/qt/src/importfromkeyserverjob.h
@@ -0,0 +1,84 @@
+/*
+ importfromkeyserverjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_IMPORTFROMKEYSERVERJOB_H__
+#define __KLEO_IMPORTFROMKEYSERVERJOB_H__
+
+#include "abstractimportjob.h"
+#include "qgpgme_export.h"
+
+namespace GpgME
+{
+class Key;
+class Error;
+class ImportResult;
+}
+
+#include <vector>
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous keyserver-importers
+
+ To use a ImportJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the import with a call
+ to start(). This call might fail, in which case the ImportJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ImportJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ImportFromKeyserverJob : public AbstractImportJob
+{
+ Q_OBJECT
+protected:
+ explicit ImportFromKeyserverJob(QObject *parent);
+public:
+ ~ImportFromKeyserverJob();
+
+ /**
+ Starts the importing operation. \a keyData contains the data to
+ import from.
+ */
+ virtual GpgME::Error start(const std::vector<GpgME::Key> &keys) = 0;
+
+ virtual GpgME::ImportResult exec(const std::vector<GpgME::Key> &keys) = 0;
+};
+
+}
+
+#endif // __KLEO_IMPORTFROMKEYSERVERJOB_H__
diff --git a/lang/qt/src/importjob.h b/lang/qt/src/importjob.h
new file mode 100644
index 0000000..5c7b24d
--- /dev/null
+++ b/lang/qt/src/importjob.h
@@ -0,0 +1,83 @@
+/*
+ importjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_IMPORTJOB_H__
+#define __KLEO_IMPORTJOB_H__
+
+#include "abstractimportjob.h"
+#include "qgpgme_export.h"
+
+#include <QtCore/QByteArray>
+
+namespace GpgME
+{
+class Error;
+class ImportResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous importers
+
+ To use a ImportJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the import with a call
+ to start(). This call might fail, in which case the ImportJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the ImportJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT ImportJob : public AbstractImportJob
+{
+ Q_OBJECT
+protected:
+ explicit ImportJob(QObject *parent);
+public:
+ ~ImportJob();
+
+ /**
+ Starts the importing operation. \a keyData contains the data to
+ import from.
+ */
+ virtual GpgME::Error start(const QByteArray &keyData) = 0;
+
+ virtual GpgME::ImportResult exec(const QByteArray &keyData) = 0;
+};
+
+}
+
+#endif // __KLEO_IMPORTJOB_H__
diff --git a/lang/qt/src/job.cpp b/lang/qt/src/job.cpp
new file mode 100644
index 0000000..8936ea5
--- /dev/null
+++ b/lang/qt/src/job.cpp
@@ -0,0 +1,159 @@
+/*
+ job.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "job.h"
+
+#include "keylistjob.h"
+#include "listallkeysjob.h"
+#include "encryptjob.h"
+#include "decryptjob.h"
+#include "decryptverifyjob.h"
+#include "signjob.h"
+#include "signkeyjob.h"
+#include "signencryptjob.h"
+#include "verifydetachedjob.h"
+#include "verifyopaquejob.h"
+#include "keygenerationjob.h"
+#include "importjob.h"
+#include "importfromkeyserverjob.h"
+#include "exportjob.h"
+#include "changeexpiryjob.h"
+#include "changeownertrustjob.h"
+#include "changepasswdjob.h"
+#include "downloadjob.h"
+#include "deletejob.h"
+#include "refreshkeysjob.h"
+#include "adduseridjob.h"
+#include "specialjob.h"
+#include "keyformailboxjob.h"
+#include "wkspublishjob.h"
+#include "tofupolicyjob.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+
+#include <gpg-error.h>
+
+QGpgME::Job::Job(QObject *parent)
+ : QObject(parent)
+{
+ if (QCoreApplication *app = QCoreApplication::instance()) {
+ connect(app, &QCoreApplication::aboutToQuit, this, &Job::slotCancel);
+ }
+}
+
+QGpgME::Job::~Job()
+{
+
+}
+
+QString QGpgME::Job::auditLogAsHtml() const
+{
+ qDebug() << "QGpgME::Job::auditLogAsHtml() should be reimplemented in Kleo::Job subclasses!";
+ return QString();
+}
+
+GpgME::Error QGpgME::Job::auditLogError() const
+{
+ qDebug() << "QGpgME::Job::auditLogError() should be reimplemented in Kleo::Job subclasses!";
+ return GpgME::Error::fromCode(GPG_ERR_NOT_IMPLEMENTED);
+}
+
+bool QGpgME::Job::isAuditLogSupported() const
+{
+ return auditLogError().code() != GPG_ERR_NOT_IMPLEMENTED;
+}
+
+#define make_job_subclass_ext(x,y) \
+ QGpgME::x::x( QObject * parent ) : y( parent ) {} \
+ QGpgME::x::~x() {}
+
+#define make_job_subclass(x) make_job_subclass_ext(x,Job)
+
+make_job_subclass(KeyListJob)
+make_job_subclass(ListAllKeysJob)
+make_job_subclass(EncryptJob)
+make_job_subclass(DecryptJob)
+make_job_subclass(DecryptVerifyJob)
+make_job_subclass(SignJob)
+make_job_subclass(SignEncryptJob)
+make_job_subclass(SignKeyJob)
+make_job_subclass(VerifyDetachedJob)
+make_job_subclass(VerifyOpaqueJob)
+make_job_subclass(KeyGenerationJob)
+make_job_subclass(AbstractImportJob)
+make_job_subclass_ext(ImportJob, AbstractImportJob)
+make_job_subclass_ext(ImportFromKeyserverJob, AbstractImportJob)
+make_job_subclass(ExportJob)
+make_job_subclass(ChangeExpiryJob)
+make_job_subclass(ChangeOwnerTrustJob)
+make_job_subclass(ChangePasswdJob)
+make_job_subclass(DownloadJob)
+make_job_subclass(DeleteJob)
+make_job_subclass(RefreshKeysJob)
+make_job_subclass(AddUserIDJob)
+make_job_subclass(SpecialJob)
+make_job_subclass(KeyForMailboxJob)
+make_job_subclass(WKSPublishJob)
+make_job_subclass(TofuPolicyJob)
+
+#undef make_job_subclass
+
+#include "job.moc"
+
+#include "keylistjob.moc"
+#include "listallkeysjob.moc"
+#include "encryptjob.moc"
+#include "decryptjob.moc"
+#include "decryptverifyjob.moc"
+#include "signjob.moc"
+#include "signencryptjob.moc"
+#include "signkeyjob.moc"
+#include "verifydetachedjob.moc"
+#include "verifyopaquejob.moc"
+#include "keygenerationjob.moc"
+#include "abstractimportjob.moc"
+#include "importjob.moc"
+#include "importfromkeyserverjob.moc"
+#include "exportjob.moc"
+#include "changeexpiryjob.moc"
+#include "changeownertrustjob.moc"
+#include "changepasswdjob.moc"
+#include "downloadjob.moc"
+#include "deletejob.moc"
+#include "refreshkeysjob.moc"
+#include "adduseridjob.moc"
+#include "specialjob.moc"
+#include "keyformailboxjob.moc"
+#include "wkspublishjob.moc"
+#include "tofupolicyjob.moc"
diff --git a/lang/qt/src/job.h b/lang/qt/src/job.h
new file mode 100644
index 0000000..5767729
--- /dev/null
+++ b/lang/qt/src/job.h
@@ -0,0 +1,92 @@
+/*
+ job.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_JOB_H__
+#define __KLEO_JOB_H__
+
+#include "qgpgme_export.h"
+
+#include <QObject>
+#include <QString>
+
+#ifdef BUILDING_QGPGME
+# include "error.h"
+#else
+# include <gpgme++/error.h>
+#endif
+
+class QWidget;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous crypto operations
+
+ During the operation, you might receive progress updates through
+ the progress() signal as they arrive, but an implementation is
+ free to not send progress information. You should show a busy
+ progressbar until the first progress() signal is received.
+
+ The done() signal is emitted _before_ the result() signals of
+ subclasses and should be used to hide and/or reset progress bars,
+ not to learn of the end of the operation. Use the result()
+ signals for that.
+
+ To cancel the operation, simply call slotCancel(). The result()
+ signal of subclasses will still be emitted, though, and will
+ carry the information that the operation was canceled.
+*/
+class QGPGME_EXPORT Job : public QObject
+{
+ Q_OBJECT
+protected:
+ explicit Job(QObject *parent);
+public:
+ ~Job();
+
+ virtual QString auditLogAsHtml() const;
+ virtual GpgME::Error auditLogError() const;
+ bool isAuditLogSupported() const;
+
+public Q_SLOTS:
+ virtual void slotCancel() = 0;
+
+Q_SIGNALS:
+ void progress(const QString &what, int current, int total);
+ void done();
+};
+
+}
+
+#endif // __KLEO_JOB_H__
diff --git a/lang/qt/src/keyformailboxjob.h b/lang/qt/src/keyformailboxjob.h
new file mode 100644
index 0000000..d8b6c6b
--- /dev/null
+++ b/lang/qt/src/keyformailboxjob.h
@@ -0,0 +1,106 @@
+/*
+ keyformailboxjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef __KLEO_KEYFORMAILBOX_H__
+#define __KLEO_KEYFORMAILBOX_H__
+
+#include <QString>
+
+#include "job.h"
+
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+# include <gpgme++/key.h>
+#endif
+
+namespace GpgME
+{
+class Error;
+class KeyListResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short Get the best key to use for a Mailbox
+
+ To use the keyformailboxjob, first obtain an instance from the
+ CryptoBackend and either exec it or start and
+ conncet the result() signals to a suitable slot.
+ The job will be automatically deleted in which
+ case the KeylistJob instance will have schedules it's own
+ destruction with a call to QObject::deleteLater().
+
+ The best key is defined as the key with a UID that has an
+ E-Mail that matches the mailbox provided. If multiple
+ keys are found the one with the highest validity is returned.
+
+ After result() is emitted, the
+ KeyListJob will schedule it's own destruction by calling
+ QObject::deleteLater().
+*/
+class QGPGME_EXPORT KeyForMailboxJob: public Job
+{
+ Q_OBJECT
+protected:
+ explicit KeyForMailboxJob(QObject *parent);
+
+public:
+ ~KeyForMailboxJob();
+
+ /**
+ Starts the operation. \a mailbox is the mailbox to
+ look for.
+
+ The result is the same as for the LocateKeysJob.
+
+ If \a canEncrypt is true, only keys that have a subkey for encryption
+ usage are returned. Use this if you need to select a
+ key for signing.
+ */
+ virtual GpgME::Error start(const QString &mailbox, bool canEncrypt = true) = 0;
+
+ virtual GpgME::KeyListResult exec(const QString &mailbox, bool canEncrypt, GpgME::Key &key, GpgME::UserID &uid) = 0;
+
+Q_SIGNALS:
+ /** The result. \a Key is the key found or a Null key.
+ *
+ * The userid is the uid where the mailbox matches.
+ *
+ * The auditlog params are always null / empty.
+ */
+ void result(const GpgME::KeyListResult &result, const GpgME::Key &key, const GpgME::UserID &uid, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+#endif
diff --git a/lang/qt/src/keygenerationjob.h b/lang/qt/src/keygenerationjob.h
new file mode 100644
index 0000000..a0beeac
--- /dev/null
+++ b/lang/qt/src/keygenerationjob.h
@@ -0,0 +1,85 @@
+/*
+ keygenerationjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_KEYGENERATIONJOB_H__
+#define __KLEO_KEYGENERATIONJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#include <QtCore/QByteArray>
+
+namespace GpgME
+{
+class Error;
+class KeyGenerationResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous key generation
+
+ To use a KeyGenerationJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the key generation with
+ a call to start(). This call might fail, in which case the
+ KeyGenerationJob instance will have scheduled it's own
+ destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the KeyGenerationJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT KeyGenerationJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit KeyGenerationJob(QObject *parent);
+public:
+ ~KeyGenerationJob();
+
+ /**
+ Starts the key generation operation. \a parameters is a
+ backend-specific string containing the parameters of the key to
+ create (length, capabilities, etc).
+ */
+ virtual GpgME::Error start(const QString &parameters) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::KeyGenerationResult &result, const QByteArray &pubKeyData, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_KEYGENERATIONJOB_H__
diff --git a/lang/qt/src/keylistjob.h b/lang/qt/src/keylistjob.h
new file mode 100644
index 0000000..8dc736e
--- /dev/null
+++ b/lang/qt/src/keylistjob.h
@@ -0,0 +1,109 @@
+/*
+ keylistjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_KEYLISTJOB_H__
+#define __KLEO_KEYLISTJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+# include <gpgme++/key.h>
+#endif
+
+#include <vector>
+
+namespace GpgME
+{
+class Error;
+class KeyListResult;
+}
+
+class QStringList;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous key listers
+
+ To use a KeyListJob, first obtain an instance from the
+ CryptoBackend implementation, connect the nextKey(), progress()
+ and result() signals to suitable slots and then start the key
+ listing with a call to start(). This call might fail, in which
+ case the KeylistJob instance will have schedules it's own
+ destruction with a call to QObject::deleteLater().
+
+ During keylisting, you will receive new key objects through the
+ nextKey() signal as they arrive. After result() is emitted, the
+ KeyListJob will schedule it's own destruction by calling
+ QObject::deleteLater().
+*/
+class QGPGME_EXPORT KeyListJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit KeyListJob(QObject *parent);
+
+public:
+ ~KeyListJob();
+
+ /**
+ Starts the keylist operation. \a pattern is a list of patterns
+ used to restrict the list of keys returned. Empty patterns are
+ ignored. If \a pattern is empty or contains only empty strings,
+ all keys are returned (however, the backend is free to truncate
+ the result and should do so; when this happens, it will be
+ reported by the reult object).
+
+ If \a secretOnly is true, only keys for which the secret key is
+ also available are returned. Use this if you need to select a
+ key for signing.
+ */
+ virtual GpgME::Error start(const QStringList &patterns, bool secretOnly = false) = 0;
+
+ virtual GpgME::KeyListResult exec(const QStringList &patterns, bool secretOnly, std::vector<GpgME::Key> &keys) = 0;
+
+ /** Add a flag to the keylistmode used. */
+ virtual void addMode(GpgME::KeyListMode mode) = 0;
+
+Q_SIGNALS:
+ void nextKey(const GpgME::Key &key);
+ void result(const GpgME::KeyListResult &result, const std::vector<GpgME::Key> &keys = std::vector<GpgME::Key>(), const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_KEYLISTJOB_H__
diff --git a/lang/qt/src/listallkeysjob.h b/lang/qt/src/listallkeysjob.h
new file mode 100644
index 0000000..4fbb469
--- /dev/null
+++ b/lang/qt/src/listallkeysjob.h
@@ -0,0 +1,104 @@
+/*
+ listallkeysjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_LISTALLKEYSJOB_H__
+#define __KLEO_LISTALLKEYSJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+# include <gpgme++/key.h>
+#endif
+
+#include <vector>
+
+namespace GpgME
+{
+class Error;
+class KeyListResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronously listing all keys
+
+ To use a ListAllKeysJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress()
+ and result() signals to suitable slots and then start the key
+ listing with a call to start(). This call might fail, in which
+ case the ListAllKeysJob instance will have schedules it's own
+ destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the ListAllKeysJob will schedule it's
+ own destruction by calling QObject::deleteLater().
+
+ This is potentially much faster than a KeyListJob with empty
+ pattern.
+*/
+class QGPGME_EXPORT ListAllKeysJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit ListAllKeysJob(QObject *parent);
+
+public:
+ ~ListAllKeysJob();
+
+ /**
+ Starts the listallkeys operation. In general, all keys are
+ returned (however, the backend is free to truncate the result
+ and should do so; when this happens, it will be reported by the
+ result object).
+
+ If \a mergeKeys is true, secret keys are merged into public
+ keys.
+ */
+ virtual GpgME::Error start(bool mergeKeys = false) = 0;
+
+ /**
+ Synchronous version of start().
+ */
+ virtual GpgME::KeyListResult exec(std::vector<GpgME::Key> &pub, std::vector<GpgME::Key> &sec, bool mergeKeys = false) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::KeyListResult &result, const std::vector<GpgME::Key> &pub = std::vector<GpgME::Key>(), const std::vector<GpgME::Key> &sec = std::vector<GpgME::Key>(), const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_LISTALLKEYSJOB_H__
diff --git a/lang/qt/src/multideletejob.h b/lang/qt/src/multideletejob.h
new file mode 100644
index 0000000..8915cd1
--- /dev/null
+++ b/lang/qt/src/multideletejob.h
@@ -0,0 +1,107 @@
+/*
+ multideletejob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_MULTIDELETEJOB_H__
+#define __KLEO_MULTIDELETEJOB_H__
+
+#include "qgpgme_export.h"
+#include "job.h"
+#include "cryptobackend.h"
+
+#include <QPointer>
+
+#include <vector>
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+class DeleteJob;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short A convenience class bundling together multiple DeleteJobs.
+
+ To use a MultiDeleteJob, pass it a CryptoBackend implementation,
+ connect the progress() and result() signals to suitable slots and
+ then start the delete with a call to start(). This call might
+ fail, in which case the MultiDeleteJob instance will have scheduled
+ it's own destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the MultiDeleteJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT MultiDeleteJob : public Job
+{
+ Q_OBJECT
+public:
+ explicit MultiDeleteJob(const Protocol *protocol);
+ ~MultiDeleteJob();
+
+ /**
+ Starts the delete operation. \a keys is the list of keys to
+ delete, \a allowSecretKeyDeletion specifies if a key may also
+ be deleted if the secret key part is available, too.
+ */
+ GpgME::Error start(const std::vector<GpgME::Key> &keys, bool allowSecretKeyDeletion = false);
+
+ /* from Job */
+ void slotCancel() Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const GpgME::Key &errorKey);
+
+private Q_SLOTS:
+ void slotResult(const GpgME::Error &);
+
+private:
+ GpgME::Error startAJob();
+
+private:
+ const Protocol *mProtocol;
+ QPointer<DeleteJob> mJob;
+ std::vector<GpgME::Key> mKeys;
+ std::vector<GpgME::Key>::const_iterator mIt;
+ bool mAllowSecretKeyDeletion;
+};
+
+}
+
+#endif // __KLEO_MULTIDELETEJOB_H__
diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h
new file mode 100644
index 0000000..40ddcb5
--- /dev/null
+++ b/lang/qt/src/protocol.h
@@ -0,0 +1,183 @@
+/*
+ protocol.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef __QGPGME_PROTOCOL_H__
+#define __QGPGME_PROTOCOL_H__
+
+#include <QString>
+#include <QVariant>
+
+#include "qgpgme_export.h"
+
+namespace QGpgME {
+class CryptoConfig;
+class KeyListJob;
+class ListAllKeysJob;
+class KeyGenerationJob;
+class ImportJob;
+class ImportFromKeyserverJob;
+class ExportJob;
+class DownloadJob;
+class DeleteJob;
+class EncryptJob;
+class DecryptJob;
+class SignJob;
+class SignKeyJob;
+class VerifyDetachedJob;
+class VerifyOpaqueJob;
+class SignEncryptJob;
+class DecryptVerifyJob;
+class RefreshKeysJob;
+class ChangeExpiryJob;
+class ChangeOwnerTrustJob;
+class ChangePasswdJob;
+class AddUserIDJob;
+class SpecialJob;
+class KeyForMailboxJob;
+class WKSPublishJob;
+class TofuPolicyJob;
+
+/** The main entry point for QGpgME Comes in OpenPGP and SMIME(CMS) flavors.
+ *
+ * Use the proctocol class to obtain an instance of a job. Jobs
+ * provide async API for GnuPG that can be connected to signals / slots.
+ *
+ * A job is usually started with start() and emits a result signal.
+ * The parameters of the result signal depend on the job but the last
+ * two are always a QString for the auditlog and an GpgME::Error for
+ * an eventual error.
+ *
+ * In case async API is used and the result signal is emited a
+ * job schedules its own deletion.
+ *
+ * Most jobs also provide a synchronous call exec in which case
+ * you have to explicitly delete the job if you don't need it anymore.
+ *
+ * \code
+ * // Async example:
+ * KeyListJob *job = openpgp()->keyListJob();
+ * connect(job, &KeyListJob::result, job, [this, job](KeyListResult, std::vector<Key> keys, QString, Error)
+ * {
+ * // keys and resuls can now be used.
+ * });
+ * \endcode
+ *
+ * \code
+ * // Sync eaxmple:
+ * KeyListJob *job = openpgp()->keyListJob(false, false, false);
+ * std::vector<GpgME::Key> keys;
+ * GpgME::KeyListResult result = job->exec(QStringList() <<
+ * QStringLiteral("alfa@example.net"),
+ * false, keys);
+ * delete job;
+ * \endcode
+ */
+class QGPGME_EXPORT Protocol
+{
+public:
+ virtual ~Protocol() {}
+
+ virtual QString name() const = 0;
+
+ virtual QString displayName() const = 0;
+
+ virtual KeyListJob *keyListJob(bool remote = false, bool includeSigs = false, bool validate = false) const = 0;
+ virtual ListAllKeysJob *listAllKeysJob(bool includeSigs = false, bool validate = false) const = 0;
+ virtual EncryptJob *encryptJob(bool armor = false, bool textmode = false) const = 0;
+ virtual DecryptJob *decryptJob() const = 0;
+ virtual SignJob *signJob(bool armor = false, bool textMode = false) const = 0;
+ virtual VerifyDetachedJob *verifyDetachedJob(bool textmode = false) const = 0;
+ virtual VerifyOpaqueJob *verifyOpaqueJob(bool textmode = false) const = 0;
+ virtual KeyGenerationJob *keyGenerationJob() const = 0;
+ virtual ImportJob *importJob() const = 0;
+ virtual ImportFromKeyserverJob *importFromKeyserverJob() const = 0;
+ virtual ExportJob *publicKeyExportJob(bool armor = false) const = 0;
+ // @param charset the encoding of the passphrase in the exported file
+ virtual ExportJob *secretKeyExportJob(bool armor = false, const QString &charset = QString()) const = 0;
+ virtual DownloadJob *downloadJob(bool armor = false) const = 0;
+ virtual DeleteJob *deleteJob() const = 0;
+ virtual SignEncryptJob *signEncryptJob(bool armor = false, bool textMode = false) const = 0;
+ virtual DecryptVerifyJob *decryptVerifyJob(bool textmode = false) const = 0;
+ virtual RefreshKeysJob *refreshKeysJob() const = 0;
+ virtual ChangeExpiryJob *changeExpiryJob() const = 0;
+ virtual SignKeyJob *signKeyJob() const = 0;
+ virtual ChangePasswdJob *changePasswdJob() const = 0;
+ virtual ChangeOwnerTrustJob *changeOwnerTrustJob() const = 0;
+ virtual AddUserIDJob *addUserIDJob() const = 0;
+ virtual SpecialJob *specialJob(const char *type, const QMap<QString, QVariant> &args) const = 0;
+
+ /** A key locate job.
+ *
+ * This tries to find a key in local
+ * and remote sources, if the key was remote it is imported
+ * by GnuPG. Same as KeyListJob but intended to be used
+ * to locate keys automatically. This ends up calling --locate-keys.
+ *
+ * Only available for OpenPGP
+ *
+ * Results are validated. As if keyListJob was called
+ * with both includeSigs and validate options.
+ */
+ virtual KeyListJob *locateKeysJob() const = 0;
+ /** Find the best key to use for a mailbox. */
+ virtual KeyForMailboxJob *keyForMailboxJob() const = 0;
+
+ /** A Job for interacting with gnupg's wks tools. */
+ virtual WKSPublishJob *wksPublishJob() const = 0;
+
+ /** A Job to set tofu policy */
+ virtual TofuPolicyJob *tofuPolicyJob() const = 0;
+};
+
+/** Obtain a reference to the OpenPGP Protocol.
+ *
+ * The reference is to a static object.
+ * @returns Refrence to the OpenPGP Protocol.
+ */
+QGPGME_EXPORT Protocol *openpgp();
+
+/** Obtain a reference to the smime Protocol.
+ *
+ * The reference is to a static object.
+ * @returns Refrence to the smime Protocol.
+ */
+QGPGME_EXPORT Protocol *smime();
+
+/** Obtain a reference to a cryptoConfig object.
+ *
+ * The reference is to a static object.
+ * @returns reference to cryptoConfig object.
+ */
+QGPGME_EXPORT CryptoConfig *cryptoConfig();
+
+}
+#endif
diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h
new file mode 100644
index 0000000..7f66fa4
--- /dev/null
+++ b/lang/qt/src/protocol_p.h
@@ -0,0 +1,419 @@
+/*
+ protocol_p.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef __QGPGME_PROTOCOL_P_H__
+#define __QGPGME_PROTOCOL_P_H__
+#include "qgpgmenewcryptoconfig.h"
+
+#include "qgpgmekeygenerationjob.h"
+#include "qgpgmekeylistjob.h"
+#include "qgpgmelistallkeysjob.h"
+#include "qgpgmedecryptjob.h"
+#include "qgpgmedecryptverifyjob.h"
+#include "qgpgmerefreshkeysjob.h"
+#include "qgpgmedeletejob.h"
+#include "qgpgmesecretkeyexportjob.h"
+#include "qgpgmedownloadjob.h"
+#include "qgpgmesignencryptjob.h"
+#include "qgpgmeencryptjob.h"
+#include "qgpgmesignjob.h"
+#include "qgpgmesignkeyjob.h"
+#include "qgpgmeexportjob.h"
+#include "qgpgmeverifydetachedjob.h"
+#include "qgpgmeimportjob.h"
+#include "qgpgmeimportfromkeyserverjob.h"
+#include "qgpgmeverifyopaquejob.h"
+#include "qgpgmechangeexpiryjob.h"
+#include "qgpgmechangeownertrustjob.h"
+#include "qgpgmechangepasswdjob.h"
+#include "qgpgmeadduseridjob.h"
+#include "qgpgmekeyformailboxjob.h"
+#include "qgpgmewkspublishjob.h"
+#include "qgpgmetofupolicyjob.h"
+
+namespace
+{
+
+class Protocol : public QGpgME::Protocol
+{
+ GpgME::Protocol mProtocol;
+public:
+ explicit Protocol(GpgME::Protocol proto) : mProtocol(proto) {}
+
+ QString name() const Q_DECL_OVERRIDE
+ {
+ switch (mProtocol) {
+ case GpgME::OpenPGP: return QStringLiteral("OpenPGP");
+ case GpgME::CMS: return QStringLiteral("SMIME");
+ default: return QString();
+ }
+ }
+
+ QString displayName() const Q_DECL_OVERRIDE
+ {
+ // ah (2.4.16): Where is this used and isn't this inverted
+ // with name
+ switch (mProtocol) {
+ case GpgME::OpenPGP: return QStringLiteral("gpg");
+ case GpgME::CMS: return QStringLiteral("gpgsm");
+ default: return QStringLiteral("unknown");
+ }
+ }
+
+ QGpgME::SpecialJob *specialJob(const char *, const QMap<QString, QVariant> &) const Q_DECL_OVERRIDE
+ {
+ return 0;
+ }
+
+ QGpgME::KeyListJob *keyListJob(bool remote, bool includeSigs, bool validate) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ unsigned int mode = context->keyListMode();
+ if (remote) {
+ mode |= GpgME::Extern;
+ mode &= ~GpgME::Local;
+ } else {
+ mode |= GpgME::Local;
+ mode &= ~GpgME::Extern;
+ }
+ if (includeSigs) {
+ mode |= GpgME::Signatures;
+ }
+ if (validate) {
+ mode |= GpgME::Validate;
+ }
+ context->setKeyListMode(mode);
+ return new QGpgME::QGpgMEKeyListJob(context);
+ }
+
+ QGpgME::ListAllKeysJob *listAllKeysJob(bool includeSigs, bool validate) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ unsigned int mode = context->keyListMode();
+ mode |= GpgME::Local;
+ mode &= ~GpgME::Extern;
+ if (includeSigs) {
+ mode |= GpgME::Signatures;
+ }
+ if (validate) {
+ mode |= GpgME::Validate;
+ /* Setting the context to offline mode disables CRL / OCSP checks in
+ this Job. Otherwise we would try to fetch the CRL's for all CMS
+ keys in the users keyring because GpgME::Validate includes remote
+ resources by default in the validity check.
+ This setting only has any effect if gpgsm >= 2.1.6 is used.
+ */
+ context->setOffline(true);
+ }
+ context->setKeyListMode(mode);
+ return new QGpgME::QGpgMEListAllKeysJob(context);
+ }
+
+ QGpgME::EncryptJob *encryptJob(bool armor, bool textmode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setArmor(armor);
+ context->setTextMode(textmode);
+ return new QGpgME::QGpgMEEncryptJob(context);
+ }
+
+ QGpgME::DecryptJob *decryptJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEDecryptJob(context);
+ }
+
+ QGpgME::SignJob *signJob(bool armor, bool textMode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setArmor(armor);
+ context->setTextMode(textMode);
+ return new QGpgME::QGpgMESignJob(context);
+ }
+
+ QGpgME::VerifyDetachedJob *verifyDetachedJob(bool textMode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setTextMode(textMode);
+ return new QGpgME::QGpgMEVerifyDetachedJob(context);
+ }
+
+ QGpgME::VerifyOpaqueJob *verifyOpaqueJob(bool textMode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setTextMode(textMode);
+ return new QGpgME::QGpgMEVerifyOpaqueJob(context);
+ }
+
+ QGpgME::KeyGenerationJob *keyGenerationJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEKeyGenerationJob(context);
+ }
+
+ QGpgME::ImportJob *importJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEImportJob(context);
+ }
+
+ QGpgME::ImportFromKeyserverJob *importFromKeyserverJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEImportFromKeyserverJob(context);
+ }
+
+ QGpgME::ExportJob *publicKeyExportJob(bool armor) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setArmor(armor);
+ return new QGpgME::QGpgMEExportJob(context);
+ }
+
+ QGpgME::ExportJob *secretKeyExportJob(bool armor, const QString &charset) const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::CMS) { // fixme: add support for gpg, too
+ return 0;
+ }
+
+ // this operation is not supported by gpgme, so we have to call gpgsm ourselves:
+ return new QGpgME::QGpgMESecretKeyExportJob(armor, charset);
+ }
+
+ QGpgME::RefreshKeysJob *refreshKeysJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::CMS) { // fixme: add support for gpg, too
+ return 0;
+ }
+
+ // this operation is not supported by gpgme, so we have to call gpgsm ourselves:
+ return new QGpgME::QGpgMERefreshKeysJob();
+ }
+
+ QGpgME::DownloadJob *downloadJob(bool armor) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setArmor(armor);
+ // this is the hackish interface for downloading from keyserers currently:
+ context->setKeyListMode(GpgME::Extern);
+ return new QGpgME::QGpgMEDownloadJob(context);
+ }
+
+ QGpgME::DeleteJob *deleteJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEDeleteJob(context);
+ }
+
+ QGpgME::SignEncryptJob *signEncryptJob(bool armor, bool textMode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setArmor(armor);
+ context->setTextMode(textMode);
+ return new QGpgME::QGpgMESignEncryptJob(context);
+ }
+
+ QGpgME::DecryptVerifyJob *decryptVerifyJob(bool textMode) const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+
+ context->setTextMode(textMode);
+ return new QGpgME::QGpgMEDecryptVerifyJob(context);
+ }
+
+ QGpgME::ChangeExpiryJob *changeExpiryJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return 0; // only supported by gpg
+ }
+
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEChangeExpiryJob(context);
+ }
+
+ QGpgME::ChangePasswdJob *changePasswdJob() const Q_DECL_OVERRIDE
+ {
+ if (!GpgME::hasFeature(GpgME::PasswdFeature, 0)) {
+ return 0;
+ }
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEChangePasswdJob(context);
+ }
+
+ QGpgME::SignKeyJob *signKeyJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return 0; // only supported by gpg
+ }
+
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMESignKeyJob(context);
+ }
+
+ QGpgME::ChangeOwnerTrustJob *changeOwnerTrustJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return 0; // only supported by gpg
+ }
+
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEChangeOwnerTrustJob(context);
+ }
+
+ QGpgME::AddUserIDJob *addUserIDJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return 0; // only supported by gpg
+ }
+
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return 0;
+ }
+ return new QGpgME::QGpgMEAddUserIDJob(context);
+ }
+
+ QGpgME::KeyListJob *locateKeysJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return Q_NULLPTR;
+ }
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return Q_NULLPTR;
+ }
+ context->setKeyListMode(GpgME::Extern | GpgME::Local | GpgME::Signatures | GpgME::Validate);
+ return new QGpgME::QGpgMEKeyListJob(context);
+ }
+
+ QGpgME::KeyForMailboxJob *keyForMailboxJob() const Q_DECL_OVERRIDE
+ {
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return Q_NULLPTR;
+ }
+ return new QGpgME::QGpgMEKeyForMailboxJob(context);
+ }
+
+ QGpgME::WKSPublishJob *wksPublishJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return Q_NULLPTR;
+ }
+ auto context = GpgME::Context::createForEngine(GpgME::SpawnEngine);
+ if (!context) {
+ return Q_NULLPTR;
+ }
+ return new QGpgME::QGpgMEWKSPublishJob(context.release());
+ }
+
+ QGpgME::TofuPolicyJob *tofuPolicyJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return Q_NULLPTR;
+ }
+ GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+ if (!context) {
+ return Q_NULLPTR;
+ }
+ return new QGpgME::QGpgMETofuPolicyJob(context);
+ }
+};
+
+}
+#endif
diff --git a/lang/qt/src/qgpgme_export.h b/lang/qt/src/qgpgme_export.h
new file mode 100644
index 0000000..ceb3888
--- /dev/null
+++ b/lang/qt/src/qgpgme_export.h
@@ -0,0 +1,73 @@
+/*qgpgme_export.h - Export macros for qgpgme
+ Copyright (C) 2016, Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef QGPGME_EXPORT_H
+#define QGPGME_EXPORT_H
+
+#ifdef QGPGME_STATIC_DEFINE
+# define QGPGME_EXPORT
+# define QGPGME_NO_EXPORT
+#else
+# ifndef QGPGME_EXPORT
+# ifdef BUILDING_QGPGME
+ /* We are building this library */
+# ifdef WIN32
+# define QGPGME_EXPORT __declspec(dllexport)
+# else
+# define QGPGME_EXPORT __attribute__((visibility("default")))
+# endif
+# else
+ /* We are using this library */
+# ifdef WIN32
+# define QGPGME_EXPORT __declspec(dllimport)
+# else
+# define QGPGME_EXPORT __attribute__((visibility("default")))
+# endif
+# endif
+# endif
+
+# ifndef QGPGME_NO_EXPORT
+# ifdef WIN32
+# define QGPGME_NO_EXPORT
+# else
+# define QGPGME_NO_EXPORT __attribute__((visibility("hidden")))
+# endif
+# endif
+#endif
+
+#ifndef QGPGME_DEPRECATED
+# define QGPGME_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#ifndef QGPGME_DEPRECATED_EXPORT
+# define QGPGME_DEPRECATED_EXPORT QGPGME_EXPORT QGPGME_DEPRECATED
+#endif
+
+#ifndef QGPGME_DEPRECATED_NO_EXPORT
+# define QGPGME_DEPRECATED_NO_EXPORT QGPGME_NO_EXPORT QGPGME_DEPRECATED
+#endif
+
+#define DEFINE_NO_DEPRECATED 0
+#if DEFINE_NO_DEPRECATED
+# define QGPGME_NO_DEPRECATED
+#endif
+
+#endif
diff --git a/lang/qt/src/qgpgme_version.h.in b/lang/qt/src/qgpgme_version.h.in
new file mode 100644
index 0000000..9fbe965
--- /dev/null
+++ b/lang/qt/src/qgpgme_version.h.in
@@ -0,0 +1,32 @@
+/*qgpgme_version.h - Version macros for qgpgme
+ Copyright (C) 2016, Intevation 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 Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ GPGME++ is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with GPGME++; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef QGPGME_VERSION_H
+#define QGPGME_VERSION_H
+
+#define QGPGME_VERSION_STRING "@LIBQGPGME_LT_CURRENT@.@LIBQGPGME_LT_AGE@.@LIBQGPGME_LT_REVISION@"
+#define QGPGME_VERSION_MAJOR @LIBQGPGME_LT_CURRENT@
+#define QGPGME_VERSION_MINOR @LIBQGPGME_LT_AGE@
+#define QGPGME_VERSION_PATCH @LIBQGPGME_LT_REVISION@
+#define QGPGME_VERSION ((@LIBQGPGME_LT_CURRENT@<<16)|(@LIBQGPGME_LT_AGE@<<8)|(@LIBQGPGME_LT_REVISION@))
+
+#endif
diff --git a/lang/qt/src/qgpgmeadduseridjob.cpp b/lang/qt/src/qgpgmeadduseridjob.cpp
new file mode 100644
index 0000000..eb3bfab
--- /dev/null
+++ b/lang/qt/src/qgpgmeadduseridjob.cpp
@@ -0,0 +1,80 @@
+/*
+ qgpgmeadduseridjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeadduseridjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "gpgadduserideditinteractor.h"
+#include "key.h"
+
+#include <cassert>
+#include <memory>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEAddUserIDJob::QGpgMEAddUserIDJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEAddUserIDJob::~QGpgMEAddUserIDJob() {}
+
+static QGpgMEAddUserIDJob::result_type add_user_id(Context *ctx, const Key &key, const QString &name, const QString &email, const QString &comment)
+{
+
+ GpgAddUserIDEditInteractor *gau = new GpgAddUserIDEditInteractor;
+
+ gau->setNameUtf8(name.toUtf8().constData());
+ gau->setEmailUtf8(email.toUtf8().constData());
+ gau->setCommentUtf8(comment.toUtf8().constData());
+
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+ assert(!data.isNull());
+ const Error err = ctx->edit(key, std::unique_ptr<EditInteractor> (gau), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMEAddUserIDJob::start(const Key &key, const QString &name, const QString &email, const QString &comment)
+{
+ run(std::bind(&add_user_id, std::placeholders::_1, key, name, email, comment));
+ return Error();
+}
+#include "qgpgmeadduseridjob.moc"
diff --git a/lang/qt/src/qgpgmeadduseridjob.h b/lang/qt/src/qgpgmeadduseridjob.h
new file mode 100644
index 0000000..294eb6c
--- /dev/null
+++ b/lang/qt/src/qgpgmeadduseridjob.h
@@ -0,0 +1,65 @@
+/*
+ qgpgmeadduseridjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEADDUSERIDJOB_H__
+#define __QGPGME_QGPGMEADDUSERIDJOB_H__
+
+#include "adduseridjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEAddUserIDJob
+#ifdef Q_MOC_RUN
+ : public AddUserIDJob
+#else
+ : public _detail::ThreadedJobMixin<AddUserIDJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEAddUserIDJob(GpgME::Context *context);
+ ~QGpgMEAddUserIDJob();
+
+ /* from AddUserIDJob */
+ GpgME::Error start(const GpgME::Key &key, const QString &name, const QString &email, const QString &comment) Q_DECL_OVERRIDE;
+};
+}
+
+#endif // __QGPGME_QGPGMEADDUSERIDJOB_H__
diff --git a/lang/qt/src/qgpgmebackend.cpp b/lang/qt/src/qgpgmebackend.cpp
new file mode 100644
index 0000000..797e58a
--- /dev/null
+++ b/lang/qt/src/qgpgmebackend.cpp
@@ -0,0 +1,203 @@
+/*
+ qgpgmebackend.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmebackend.h"
+
+
+#include "error.h"
+#include "engineinfo.h"
+
+#include "protocol_p.h"
+
+#include <QFile>
+#include <QString>
+
+const char QGpgME::QGpgMEBackend::OpenPGP[] = "OpenPGP";
+const char QGpgME::QGpgMEBackend::SMIME[] = "SMIME";
+
+
+QGpgME::QGpgMEBackend::QGpgMEBackend()
+ : mCryptoConfig(0),
+ mOpenPGPProtocol(0),
+ mSMIMEProtocol(0)
+{
+ GpgME::initializeLibrary();
+}
+
+QGpgME::QGpgMEBackend::~QGpgMEBackend()
+{
+ delete mCryptoConfig; mCryptoConfig = 0;
+ delete mOpenPGPProtocol; mOpenPGPProtocol = 0;
+ delete mSMIMEProtocol; mSMIMEProtocol = 0;
+}
+
+QString QGpgME::QGpgMEBackend::name() const
+{
+ return QStringLiteral("gpgme");
+}
+
+QString QGpgME::QGpgMEBackend::displayName() const
+{
+ return QStringLiteral("GpgME");
+}
+
+QGpgME::CryptoConfig *QGpgME::QGpgMEBackend::config() const
+{
+ if (!mCryptoConfig) {
+ if (GpgME::hasFeature(GpgME::GpgConfEngineFeature, 0)) {
+ mCryptoConfig = new QGpgMENewCryptoConfig;
+ }
+ }
+ return mCryptoConfig;
+}
+
+static bool check(GpgME::Protocol proto, QString *reason)
+{
+ if (!GpgME::checkEngine(proto)) {
+ return true;
+ }
+ if (!reason) {
+ return false;
+ }
+ // error, check why:
+#if 0
+Port away from localised string or delete.
+ const GpgME::EngineInfo ei = GpgME::engineInfo(proto);
+ if (ei.isNull()) {
+ *reason = i18n("GPGME was compiled without support for %1.", proto == GpgME::CMS ? QLatin1String("S/MIME") : QLatin1String("OpenPGP"));
+ } else if (ei.fileName() && !ei.version()) {
+ *reason = i18n("Engine %1 is not installed properly.", QFile::decodeName(ei.fileName()));
+ } else if (ei.fileName() && ei.version() && ei.requiredVersion())
+ *reason = i18n("Engine %1 version %2 installed, "
+ "but at least version %3 is required.",
+ QFile::decodeName(ei.fileName()), QLatin1String(ei.version()), QLatin1String(ei.requiredVersion()));
+ else {
+ *reason = i18n("Unknown problem with engine for protocol %1.", proto == GpgME::CMS ? QLatin1String("S/MIME") : QLatin1String("OpenPGP"));
+ }
+#endif
+ return false;
+}
+
+bool QGpgME::QGpgMEBackend::checkForOpenPGP(QString *reason) const
+{
+ return check(GpgME::OpenPGP, reason);
+}
+
+bool QGpgME::QGpgMEBackend::checkForSMIME(QString *reason) const
+{
+ return check(GpgME::CMS, reason);
+}
+
+bool QGpgME::QGpgMEBackend::checkForProtocol(const char *name, QString *reason) const
+{
+ if (qstricmp(name, OpenPGP) == 0) {
+ return check(GpgME::OpenPGP, reason);
+ }
+ if (qstricmp(name, SMIME) == 0) {
+ return check(GpgME::CMS, reason);
+ }
+ if (reason) {
+ *reason = QStringLiteral("Unsupported protocol \"%1\"").arg(QLatin1String(name));
+ }
+ return false;
+}
+
+QGpgME::Protocol *QGpgME::QGpgMEBackend::openpgp() const
+{
+ if (!mOpenPGPProtocol)
+ if (checkForOpenPGP()) {
+ mOpenPGPProtocol = new ::Protocol(GpgME::OpenPGP);
+ }
+ return mOpenPGPProtocol;
+}
+
+QGpgME::Protocol *QGpgME::QGpgMEBackend::smime() const
+{
+ if (!mSMIMEProtocol)
+ if (checkForSMIME()) {
+ mSMIMEProtocol = new ::Protocol(GpgME::CMS);
+ }
+ return mSMIMEProtocol;
+}
+
+QGpgME::Protocol *QGpgME::QGpgMEBackend::protocol(const char *name) const
+{
+ if (qstricmp(name, OpenPGP) == 0) {
+ return openpgp();
+ }
+ if (qstricmp(name, SMIME) == 0) {
+ return smime();
+ }
+ return 0;
+}
+
+bool QGpgME::QGpgMEBackend::supportsProtocol(const char *name) const
+{
+ return qstricmp(name, OpenPGP) == 0 || qstricmp(name, SMIME) == 0;
+}
+
+const char *QGpgME::QGpgMEBackend::enumerateProtocols(int i) const
+{
+ switch (i) {
+ case 0: return OpenPGP;
+ case 1: return SMIME;
+ default: return 0;
+ }
+}
+
+static QGpgME::QGpgMEBackend *gpgmeBackend;
+
+QGpgME::CryptoConfig *QGpgME::cryptoConfig()
+{
+ if (!gpgmeBackend) {
+ gpgmeBackend = new QGpgME::QGpgMEBackend();
+ }
+ return gpgmeBackend->config();
+
+}
+
+QGpgME::Protocol *QGpgME::openpgp()
+{
+ if (!gpgmeBackend) {
+ gpgmeBackend = new QGpgME::QGpgMEBackend();
+ }
+ return gpgmeBackend->openpgp();
+}
+
+QGpgME::Protocol *QGpgME::smime()
+{
+ if (!gpgmeBackend) {
+ gpgmeBackend = new QGpgME::QGpgMEBackend();
+ }
+ return gpgmeBackend->smime();
+}
diff --git a/lang/qt/src/qgpgmebackend.h b/lang/qt/src/qgpgmebackend.h
new file mode 100644
index 0000000..cca8b71
--- /dev/null
+++ b/lang/qt/src/qgpgmebackend.h
@@ -0,0 +1,92 @@
+/*
+ qgpgmebackend.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEBACKEND_H__
+#define __QGPGME_QGPGMEBACKEND_H__
+
+#include <QString>
+
+#include "protocol.h"
+
+class QString;
+template <typename T_Key, typename T_Value> class QMap;
+
+namespace QGpgME
+{
+class CryptoConfig;
+class Protocol;
+
+
+class QGpgMEBackend
+{
+public:
+ QGpgMEBackend();
+ ~QGpgMEBackend();
+
+ QString name() const;
+ QString displayName() const;
+
+ CryptoConfig *config() const;
+
+ Protocol *openpgp() const;
+ Protocol *smime() const;
+ Protocol *protocol(const char *name) const;
+
+ static const char OpenPGP[];
+ static const char SMIME[];
+
+ bool checkForOpenPGP(QString *reason = Q_NULLPTR) const;
+ bool checkForSMIME(QString *reason = Q_NULLPTR) const;
+ bool checkForProtocol(const char *name, QString *reason) const;
+
+ bool supportsOpenPGP() const
+ {
+ return true;
+ }
+ bool supportsSMIME() const
+ {
+ return true;
+ }
+ bool supportsProtocol(const char *name) const;
+
+ const char *enumerateProtocols(int i) const;
+
+private:
+ mutable QGpgME::CryptoConfig *mCryptoConfig;
+ mutable Protocol *mOpenPGPProtocol;
+ mutable Protocol *mSMIMEProtocol;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEBACKEND_H__
diff --git a/lang/qt/src/qgpgmechangeexpiryjob.cpp b/lang/qt/src/qgpgmechangeexpiryjob.cpp
new file mode 100644
index 0000000..43ceee3
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeexpiryjob.cpp
@@ -0,0 +1,80 @@
+/*
+ qgpgmechangeexpiryjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmechangeexpiryjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "gpgsetexpirytimeeditinteractor.h"
+#include "key.h"
+
+#include <QDateTime>
+
+#include <cassert>
+#include <memory>
+#include <string>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEChangeExpiryJob::QGpgMEChangeExpiryJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEChangeExpiryJob::~QGpgMEChangeExpiryJob() {}
+
+static QGpgMEChangeExpiryJob::result_type change_expiry(Context *ctx, const Key &key, const QDateTime &expiry)
+{
+ EditInteractor *ei = expiry.isValid()
+ ? new GpgSetExpiryTimeEditInteractor(expiry.date().toString(Qt::ISODate).toStdString())
+ : new GpgSetExpiryTimeEditInteractor();
+
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+ assert(!data.isNull());
+ const Error err = ctx->edit(key, std::unique_ptr<EditInteractor> (ei), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangeExpiryJob::start(const Key &key, const QDateTime &expiry)
+{
+ run(std::bind(&change_expiry, std::placeholders::_1, key, expiry));
+ return Error();
+}
+#include "qgpgmechangeexpiryjob.moc"
diff --git a/lang/qt/src/qgpgmechangeexpiryjob.h b/lang/qt/src/qgpgmechangeexpiryjob.h
new file mode 100644
index 0000000..4abdf78
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeexpiryjob.h
@@ -0,0 +1,66 @@
+/*
+ qgpgmechangeexpiryjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMECHANGEEXPIRYJOB_H__
+#define __QGPGME_QGPGMECHANGEEXPIRYJOB_H__
+
+#include "changeexpiryjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEChangeExpiryJob
+#ifdef Q_MOC_RUN
+ : public ChangeExpiryJob
+#else
+ : public _detail::ThreadedJobMixin<ChangeExpiryJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEChangeExpiryJob(GpgME::Context *context);
+ ~QGpgMEChangeExpiryJob();
+
+ /* from ChangeExpiryJob */
+ GpgME::Error start(const GpgME::Key &key, const QDateTime &expiry) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMECHANGEEXPIRYJOB_H__
diff --git a/lang/qt/src/qgpgmechangeownertrustjob.cpp b/lang/qt/src/qgpgmechangeownertrustjob.cpp
new file mode 100644
index 0000000..55131d9
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeownertrustjob.cpp
@@ -0,0 +1,76 @@
+/*
+ qgpgmechangeownertrustjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmechangeownertrustjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "gpgsetownertrusteditinteractor.h"
+#include "key.h"
+
+#include <cassert>
+#include <memory>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEChangeOwnerTrustJob::QGpgMEChangeOwnerTrustJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEChangeOwnerTrustJob::~QGpgMEChangeOwnerTrustJob() {}
+
+static QGpgMEChangeOwnerTrustJob::result_type change_ownertrust(Context *ctx, const Key &key, Key::OwnerTrust trust)
+{
+ EditInteractor *ei = new GpgSetOwnerTrustEditInteractor(trust);
+
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+ assert(!data.isNull());
+
+ const Error err = ctx->edit(key, std::unique_ptr<EditInteractor>(ei), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangeOwnerTrustJob::start(const Key &key, Key::OwnerTrust trust)
+{
+ run(std::bind(&change_ownertrust, std::placeholders::_1, key, trust));
+ return Error();
+}
+#include "qgpgmechangeownertrustjob.moc"
diff --git a/lang/qt/src/qgpgmechangeownertrustjob.h b/lang/qt/src/qgpgmechangeownertrustjob.h
new file mode 100644
index 0000000..7740616
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeownertrustjob.h
@@ -0,0 +1,65 @@
+/*
+ qgpgmechangeexpiryjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMECHANGEOWNERTRUSTJOB_H__
+#define __QGPGME_QGPGMECHANGEOWNERTRUSTJOB_H__
+
+#include "changeownertrustjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEChangeOwnerTrustJob
+#ifdef Q_MOC_RUN
+ : public ChangeOwnerTrustJob
+#else
+ : public _detail::ThreadedJobMixin<ChangeOwnerTrustJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEChangeOwnerTrustJob(GpgME::Context *context);
+ ~QGpgMEChangeOwnerTrustJob();
+
+ /* from ChangeOwnerTrustJob */
+ GpgME::Error start(const GpgME::Key &key, GpgME::Key::OwnerTrust trust) Q_DECL_OVERRIDE;
+};
+}
+
+#endif // __QGPGME_QGPGMECHANGEOWNERTRUSTJOB_H__
diff --git a/lang/qt/src/qgpgmechangepasswdjob.cpp b/lang/qt/src/qgpgmechangepasswdjob.cpp
new file mode 100644
index 0000000..0aec927
--- /dev/null
+++ b/lang/qt/src/qgpgmechangepasswdjob.cpp
@@ -0,0 +1,79 @@
+/*
+ qgpgmechangepasswdjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmechangepasswdjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "key.h"
+
+#include <cassert>
+#include <memory>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEChangePasswdJob::QGpgMEChangePasswdJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEChangePasswdJob::~QGpgMEChangePasswdJob() {}
+
+static QGpgMEChangePasswdJob::result_type change_passwd(Context *ctx, const Key &key)
+{
+#if 0 // in case we want to fall back to edit interactor for gpg...
+ std::unique_ptr<EditInteractor> ei(new GpgChangePasswdEditInteractor);
+
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+ assert(!data.isNull());
+ const Error err = ctx->edit(key, ei, data);
+#else
+ const Error err = ctx->passwd(key);
+#endif
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangePasswdJob::start(const Key &key)
+{
+ run(std::bind(&change_passwd, std::placeholders::_1, key));
+ return Error();
+}
+
+#include "qgpgmechangepasswdjob.moc"
diff --git a/lang/qt/src/qgpgmechangepasswdjob.h b/lang/qt/src/qgpgmechangepasswdjob.h
new file mode 100644
index 0000000..e37789e
--- /dev/null
+++ b/lang/qt/src/qgpgmechangepasswdjob.h
@@ -0,0 +1,66 @@
+/*
+ qgpgmechangepasswdjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMECHANGEPASSWDJOB_H__
+#define __QGPGME_QGPGMECHANGEPASSWDJOB_H__
+
+#include "changepasswdjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEChangePasswdJob
+#ifdef Q_MOC_RUN
+ : public ChangePasswdJob
+#else
+ : public _detail::ThreadedJobMixin<ChangePasswdJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEChangePasswdJob(GpgME::Context *context);
+ ~QGpgMEChangePasswdJob();
+
+ /* from ChangePasswdJob */
+ GpgME::Error start(const GpgME::Key &key) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMECHANGEPASSWDJOB_H__
diff --git a/lang/qt/src/qgpgmedecryptjob.cpp b/lang/qt/src/qgpgmedecryptjob.cpp
new file mode 100644
index 0000000..7116449
--- /dev/null
+++ b/lang/qt/src/qgpgmedecryptjob.cpp
@@ -0,0 +1,128 @@
+/*
+ qgpgmedecryptjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmedecryptjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "decryptionresult.h"
+#include "data.h"
+
+#include <QBuffer>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEDecryptJob::QGpgMEDecryptJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEDecryptJob::~QGpgMEDecryptJob() {}
+
+static QGpgMEDecryptJob::result_type decrypt(Context *ctx, QThread *thread,
+ const std::weak_ptr<QIODevice> &cipherText_,
+ const std::weak_ptr<QIODevice> &plainText_)
+{
+
+ const std::shared_ptr<QIODevice> cipherText = cipherText_.lock();
+ const std::shared_ptr<QIODevice> plainText = plainText_.lock();
+
+ const _detail::ToThreadMover ctMover(cipherText, thread);
+ const _detail::ToThreadMover ptMover(plainText, thread);
+
+ QGpgME::QIODeviceDataProvider in(cipherText);
+ const Data indata(&in);
+
+ if (!plainText) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ const DecryptionResult res = ctx->decrypt(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(plainText);
+ Data outdata(&out);
+
+ const DecryptionResult res = ctx->decrypt(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMEDecryptJob::result_type decrypt_qba(Context *ctx, const QByteArray &cipherText)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(cipherText);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return decrypt(ctx, 0, buffer, std::shared_ptr<QIODevice>());
+}
+
+Error QGpgMEDecryptJob::start(const QByteArray &cipherText)
+{
+ run(std::bind(&decrypt_qba, std::placeholders::_1, cipherText));
+ return Error();
+}
+
+void QGpgMEDecryptJob::start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText)
+{
+ run(std::bind(&decrypt, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), cipherText, plainText);
+}
+
+GpgME::DecryptionResult QGpgME::QGpgMEDecryptJob::exec(const QByteArray &cipherText,
+ QByteArray &plainText)
+{
+ const result_type r = decrypt_qba(context(), cipherText);
+ plainText = std::get<1>(r);
+ resultHook(r);
+ return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgMEDecryptJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+
+#include "qgpgmedecryptjob.moc"
diff --git a/lang/qt/src/qgpgmedecryptjob.h b/lang/qt/src/qgpgmedecryptjob.h
new file mode 100644
index 0000000..5335e84
--- /dev/null
+++ b/lang/qt/src/qgpgmedecryptjob.h
@@ -0,0 +1,84 @@
+/*
+ qgpgmedecryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEDECRYPTJOB_H__
+#define __QGPGME_QGPGMEDECRYPTJOB_H__
+
+#include "decryptjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "decryptionresult.h"
+#else
+#include <gpgme++/decryptionresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEDecryptJob
+#ifdef Q_MOC_RUN
+ : public DecryptJob
+#else
+ : public _detail::ThreadedJobMixin<DecryptJob, std::tuple<GpgME::DecryptionResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEDecryptJob(GpgME::Context *context);
+ ~QGpgMEDecryptJob();
+
+ /* from DecryptJob */
+ GpgME::Error start(const QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+ /* from DecryptJob */
+ void start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+ /* from DecryptJob */
+ GpgME::DecryptionResult exec(const QByteArray &cipherText,
+ QByteArray &plainText) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::DecryptionResult mResult;
+};
+
+}
+#endif // __QGPGME_QGPGMEDECRYPTJOB_H__
diff --git a/lang/qt/src/qgpgmedecryptverifyjob.cpp b/lang/qt/src/qgpgmedecryptverifyjob.cpp
new file mode 100644
index 0000000..d46a9b5
--- /dev/null
+++ b/lang/qt/src/qgpgmedecryptverifyjob.cpp
@@ -0,0 +1,135 @@
+/*
+ qgpgmedecryptverifyjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmedecryptverifyjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "decryptionresult.h"
+#include "verificationresult.h"
+#include "data.h"
+
+#include <QDebug>
+#include "gpgme_backend_debug.h"
+
+#include <QBuffer>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEDecryptVerifyJob::QGpgMEDecryptVerifyJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEDecryptVerifyJob::~QGpgMEDecryptVerifyJob() {}
+
+static QGpgMEDecryptVerifyJob::result_type decrypt_verify(Context *ctx, QThread *thread,
+ const std::weak_ptr<QIODevice> &cipherText_,
+ const std::weak_ptr<QIODevice> &plainText_)
+{
+
+ qCDebug(GPGPME_BACKEND_LOG);
+
+ const std::shared_ptr<QIODevice> cipherText = cipherText_.lock();
+ const std::shared_ptr<QIODevice> plainText = plainText_.lock();
+
+ const _detail::ToThreadMover ctMover(cipherText, thread);
+ const _detail::ToThreadMover ptMover(plainText, thread);
+
+ QGpgME::QIODeviceDataProvider in(cipherText);
+ const Data indata(&in);
+
+ if (!plainText) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ const std::pair<DecryptionResult, VerificationResult> res = ctx->decryptAndVerify(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ qCDebug(GPGPME_BACKEND_LOG) << "End no plainText. Error: " << ae;
+ return std::make_tuple(res.first, res.second, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(plainText);
+ Data outdata(&out);
+
+ const std::pair<DecryptionResult, VerificationResult> res = ctx->decryptAndVerify(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ qCDebug(GPGPME_BACKEND_LOG) << "End plainText. Error: " << ae;
+ return std::make_tuple(res.first, res.second, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMEDecryptVerifyJob::result_type decrypt_verify_qba(Context *ctx, const QByteArray &cipherText)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(cipherText);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return decrypt_verify(ctx, 0, buffer, std::shared_ptr<QIODevice>());
+}
+
+Error QGpgMEDecryptVerifyJob::start(const QByteArray &cipherText)
+{
+ run(std::bind(&decrypt_verify_qba, std::placeholders::_1, cipherText));
+ return Error();
+}
+
+void QGpgMEDecryptVerifyJob::start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText)
+{
+ run(std::bind(&decrypt_verify, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), cipherText, plainText);
+}
+
+std::pair<GpgME::DecryptionResult, GpgME::VerificationResult>
+QGpgME::QGpgMEDecryptVerifyJob::exec(const QByteArray &cipherText, QByteArray &plainText)
+{
+ const result_type r = decrypt_verify_qba(context(), cipherText);
+ plainText = std::get<2>(r);
+ resultHook(r);
+ return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgMEDecryptVerifyJob::resultHook(const result_type &tuple)
+{
+ mResult = std::make_pair(std::get<0>(tuple), std::get<1>(tuple));
+}
+#include "qgpgmedecryptverifyjob.moc"
diff --git a/lang/qt/src/qgpgmedecryptverifyjob.h b/lang/qt/src/qgpgmedecryptverifyjob.h
new file mode 100644
index 0000000..de2bce7
--- /dev/null
+++ b/lang/qt/src/qgpgmedecryptverifyjob.h
@@ -0,0 +1,89 @@
+/*
+ qgpgmedecryptverifyjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEDECRYPTVERIFYJOB_H__
+#define __QGPGME_QGPGMEDECRYPTVERIFYJOB_H__
+
+#include "decryptverifyjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "decryptionresult.h"
+#else
+#include <gpgme++/decryptionresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "verificationresult.h"
+#else
+#include <gpgme++/verificationresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEDecryptVerifyJob
+#ifdef Q_MOC_RUN
+ : public DecryptVerifyJob
+#else
+ : public _detail::ThreadedJobMixin<DecryptVerifyJob, std::tuple<GpgME::DecryptionResult, GpgME::VerificationResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEDecryptVerifyJob(GpgME::Context *context);
+ ~QGpgMEDecryptVerifyJob();
+
+ /* from DecryptVerifyJob */
+ GpgME::Error start(const QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+ /* from DecryptVerifyJob */
+ void start(const std::shared_ptr<QIODevice> &cipherText, const std::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+ /* from DecryptVerifyJob */
+ std::pair<GpgME::DecryptionResult, GpgME::VerificationResult>
+ exec(const QByteArray &cipherText, QByteArray &plainText) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ std::pair<GpgME::DecryptionResult, GpgME::VerificationResult> mResult;
+};
+
+}
+#endif // __QGPGME_QGPGMEDECRYPTVERIFYJOB_H__
diff --git a/lang/qt/src/qgpgmedeletejob.cpp b/lang/qt/src/qgpgmedeletejob.cpp
new file mode 100644
index 0000000..323aec4
--- /dev/null
+++ b/lang/qt/src/qgpgmedeletejob.cpp
@@ -0,0 +1,65 @@
+/*
+ qgpgmedeletejob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmedeletejob.h"
+
+#include "context.h"
+#include "key.h"
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEDeleteJob::QGpgMEDeleteJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEDeleteJob::~QGpgMEDeleteJob() {}
+
+static QGpgMEDeleteJob::result_type delete_key(Context *ctx, const Key &key, bool allowSecretKeyDeletion)
+{
+ const Error err = ctx->deleteKey(key, allowSecretKeyDeletion);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMEDeleteJob::start(const Key &key, bool allowSecretKeyDeletion)
+{
+ run(std::bind(&delete_key, std::placeholders::_1, key, allowSecretKeyDeletion));
+ return Error();
+}
+#include "qgpgmedeletejob.moc"
diff --git a/lang/qt/src/qgpgmedeletejob.h b/lang/qt/src/qgpgmedeletejob.h
new file mode 100644
index 0000000..992442f
--- /dev/null
+++ b/lang/qt/src/qgpgmedeletejob.h
@@ -0,0 +1,71 @@
+/*
+ qgpgmedeletejob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEDELETEJOB_H__
+#define __QGPGME_QGPGMEDELETEJOB_H__
+
+#include "deletejob.h"
+
+#include "threadedjobmixin.h"
+
+namespace GpgME
+{
+class Key;
+}
+
+namespace QGpgME
+{
+
+class QGpgMEDeleteJob
+#ifdef Q_MOC_RUN
+ : public DeleteJob
+#else
+ : public _detail::ThreadedJobMixin<DeleteJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEDeleteJob(GpgME::Context *context);
+ ~QGpgMEDeleteJob();
+
+ /* from DeleteJob */
+ GpgME::Error start(const GpgME::Key &key, bool allowSecretKeyDeletion) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEDELETEJOB_H__
diff --git a/lang/qt/src/qgpgmedownloadjob.cpp b/lang/qt/src/qgpgmedownloadjob.cpp
new file mode 100644
index 0000000..48cc907
--- /dev/null
+++ b/lang/qt/src/qgpgmedownloadjob.cpp
@@ -0,0 +1,100 @@
+/*
+ qgpgmedownloadjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmedownloadjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+
+#include <QStringList>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEDownloadJob::QGpgMEDownloadJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEDownloadJob::~QGpgMEDownloadJob() {}
+
+static QGpgMEDownloadJob::result_type download_qsl(Context *ctx, const QStringList &pats)
+{
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+
+ const _detail::PatternConverter pc(pats);
+
+ const Error err = ctx->exportPublicKeys(pc.patterns(), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, dp.data(), log, ae);
+}
+
+static QGpgMEDownloadJob::result_type download(Context *ctx, QThread *thread, const QByteArray &fpr, const std::weak_ptr<QIODevice> &keyData_)
+{
+ const std::shared_ptr<QIODevice> keyData = keyData_.lock();
+ if (!keyData) {
+ return download_qsl(ctx, QStringList(QString::fromUtf8(fpr)));
+ }
+
+ const _detail::ToThreadMover kdMover(keyData, thread);
+
+ QGpgME::QIODeviceDataProvider dp(keyData);
+ Data data(&dp);
+
+ const _detail::PatternConverter pc(fpr);
+
+ const Error err = ctx->exportPublicKeys(pc.patterns(), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, QByteArray(), log, ae);
+}
+
+Error QGpgMEDownloadJob::start(const QStringList &pats)
+{
+ run(std::bind(&download_qsl, std::placeholders::_1, pats));
+ return Error();
+}
+
+Error QGpgMEDownloadJob::start(const QByteArray &fpr, const std::shared_ptr<QIODevice> &keyData)
+{
+ run(std::bind(&download, std::placeholders::_1, std::placeholders::_2, fpr, std::placeholders::_3), keyData);
+ return Error();
+}
+#include "qgpgmedownloadjob.moc"
diff --git a/lang/qt/src/qgpgmedownloadjob.h b/lang/qt/src/qgpgmedownloadjob.h
new file mode 100644
index 0000000..4091190
--- /dev/null
+++ b/lang/qt/src/qgpgmedownloadjob.h
@@ -0,0 +1,69 @@
+/*
+ qgpgmedownloadjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEDOWNLOADJOB_H__
+#define __QGPGME_QGPGMEDOWNLOADJOB_H__
+
+#include "downloadjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEDownloadJob
+#ifdef Q_MOC_RUN
+ : public DownloadJob
+#else
+ : public _detail::ThreadedJobMixin<DownloadJob, std::tuple<GpgME::Error, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEDownloadJob(GpgME::Context *context);
+ ~QGpgMEDownloadJob();
+
+ /* from DownloadJob */
+ GpgME::Error start(const QStringList &fingerprints) Q_DECL_OVERRIDE;
+
+ /* from DownloadJob */
+ GpgME::Error start(const QByteArray &fingerprint, const std::shared_ptr<QIODevice> &keyData) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEDOWNLOADJOB_H__
diff --git a/lang/qt/src/qgpgmeencryptjob.cpp b/lang/qt/src/qgpgmeencryptjob.cpp
new file mode 100644
index 0000000..82c8ed8
--- /dev/null
+++ b/lang/qt/src/qgpgmeencryptjob.cpp
@@ -0,0 +1,170 @@
+/*
+ qgpgmeencryptjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeencryptjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "encryptionresult.h"
+#include "data.h"
+
+#include <QBuffer>
+
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEEncryptJob::QGpgMEEncryptJob(Context *context)
+ : mixin_type(context),
+ mOutputIsBase64Encoded(false)
+{
+ lateInitialization();
+}
+
+QGpgMEEncryptJob::~QGpgMEEncryptJob() {}
+
+void QGpgMEEncryptJob::setOutputIsBase64Encoded(bool on)
+{
+ mOutputIsBase64Encoded = on;
+}
+
+static QGpgMEEncryptJob::result_type encrypt(Context *ctx, QThread *thread,
+ const std::vector<Key> &recipients,
+ const std::weak_ptr<QIODevice> &plainText_,
+ const std::weak_ptr<QIODevice> &cipherText_,
+ const Context::EncryptionFlags eflags,
+ bool outputIsBsse64Encoded)
+{
+
+ const std::shared_ptr<QIODevice> plainText = plainText_.lock();
+ const std::shared_ptr<QIODevice> cipherText = cipherText_.lock();
+
+ const _detail::ToThreadMover ctMover(cipherText, thread);
+ const _detail::ToThreadMover ptMover(plainText, thread);
+
+ QGpgME::QIODeviceDataProvider in(plainText);
+ const Data indata(&in);
+
+ if (!cipherText) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const EncryptionResult res = ctx->encrypt(recipients, indata, outdata, eflags);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(cipherText);
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const EncryptionResult res = ctx->encrypt(recipients, indata, outdata, eflags);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMEEncryptJob::result_type encrypt_qba(Context *ctx, const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(plainText);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return encrypt(ctx, 0, recipients, buffer, std::shared_ptr<QIODevice>(), eflags, outputIsBsse64Encoded);
+}
+
+Error QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
+{
+ run(std::bind(&encrypt_qba, std::placeholders::_1, recipients, plainText,
+ alwaysTrust ? Context::AlwaysTrust : Context::None, mOutputIsBase64Encoded));
+ return Error();
+}
+
+void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText, const Context::EncryptionFlags eflags)
+{
+ run(std::bind(&encrypt,
+ std::placeholders::_1, std::placeholders::_2,
+ recipients,
+ std::placeholders::_3, std::placeholders::_4,
+ eflags,
+ mOutputIsBase64Encoded),
+ plainText, cipherText);
+}
+
+EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText,
+ const Context::EncryptionFlags eflags, QByteArray &cipherText)
+{
+ const result_type r = encrypt_qba(context(), recipients, plainText, eflags, mOutputIsBase64Encoded);
+ cipherText = std::get<1>(r);
+ resultHook(r);
+ return mResult;
+}
+
+void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+{
+ return start(recipients, plainText, cipherText, alwaysTrust ? Context::AlwaysTrust : Context::None);
+}
+
+EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+ return exec(recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, cipherText);
+}
+
+void QGpgMEEncryptJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+
+#if 0
+void QGpgMEEncryptJob::showErrorDialog(QWidget *parent, const QString &caption) const
+{
+ if (mResult.error() && !mResult.error().isCanceled()) {
+ MessageBox::error(parent, mResult, this, caption);
+ }
+}
+#endif
+#include "qgpgmeencryptjob.moc"
diff --git a/lang/qt/src/qgpgmeencryptjob.h b/lang/qt/src/qgpgmeencryptjob.h
new file mode 100644
index 0000000..42c1c78
--- /dev/null
+++ b/lang/qt/src/qgpgmeencryptjob.h
@@ -0,0 +1,109 @@
+/*
+ qgpgmeencryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEENCRYPTJOB_H__
+#define __QGPGME_QGPGMEENCRYPTJOB_H__
+
+#include "encryptjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "encryptionresult.h"
+#else
+#include <gpgme++/encryptionresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEEncryptJob
+#ifdef Q_MOC_RUN
+ : public EncryptJob
+#else
+ : public _detail::ThreadedJobMixin<EncryptJob, std::tuple<GpgME::EncryptionResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEEncryptJob(GpgME::Context *context);
+ ~QGpgMEEncryptJob();
+
+ /* from EncryptJob */
+ GpgME::Error start(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, bool alwaysTrust) Q_DECL_OVERRIDE;
+
+ /* from EncryptJob */
+ void start(const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText,
+ bool alwaysTrust) Q_DECL_OVERRIDE;
+
+ /* from EncryptJob */
+ GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, bool alwaysTrust,
+ QByteArray &cipherText) Q_DECL_OVERRIDE;
+ /* from EncryptJob */
+ void start(const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText,
+ const GpgME::Context::EncryptionFlags flags) Q_DECL_OVERRIDE;
+
+ /* from EncryptJob */
+ GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, const GpgME::Context::EncryptionFlags flags,
+ QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+ /* from EncryptJob */
+ void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ bool mOutputIsBase64Encoded;
+ GpgME::EncryptionResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEENCRYPTJOB_H__
diff --git a/lang/qt/src/qgpgmeexportjob.cpp b/lang/qt/src/qgpgmeexportjob.cpp
new file mode 100644
index 0000000..dfc5fc9
--- /dev/null
+++ b/lang/qt/src/qgpgmeexportjob.cpp
@@ -0,0 +1,76 @@
+/*
+ qgpgmeexportjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeexportjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "key.h"
+
+#include <QStringList>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEExportJob::QGpgMEExportJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEExportJob::~QGpgMEExportJob() {}
+
+static QGpgMEExportJob::result_type export_qba(Context *ctx, const QStringList &patterns)
+{
+
+ const _detail::PatternConverter pc(patterns);
+
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+
+ const Error err = ctx->exportPublicKeys(pc.patterns(), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, dp.data(), log, ae);
+}
+
+Error QGpgMEExportJob::start(const QStringList &patterns)
+{
+ run(std::bind(&export_qba, std::placeholders::_1, patterns));
+ return Error();
+}
+#include "qgpgmeexportjob.moc"
diff --git a/lang/qt/src/qgpgmeexportjob.h b/lang/qt/src/qgpgmeexportjob.h
new file mode 100644
index 0000000..7561054
--- /dev/null
+++ b/lang/qt/src/qgpgmeexportjob.h
@@ -0,0 +1,66 @@
+/*
+ qgpgmeexportjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEEXPORTJOB_H__
+#define __QGPGME_QGPGMEEXPORTJOB_H__
+
+#include "exportjob.h"
+
+#include "threadedjobmixin.h"
+
+namespace QGpgME
+{
+
+class QGpgMEExportJob
+#ifdef Q_MOC_RUN
+ : public ExportJob
+#else
+ : public _detail::ThreadedJobMixin<ExportJob, std::tuple<GpgME::Error, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEExportJob(GpgME::Context *context);
+ ~QGpgMEExportJob();
+
+ /* from ExportJob */
+ GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEEXPORTJOB_H__
diff --git a/lang/qt/src/qgpgmeimportfromkeyserverjob.cpp b/lang/qt/src/qgpgmeimportfromkeyserverjob.cpp
new file mode 100644
index 0000000..0f19679
--- /dev/null
+++ b/lang/qt/src/qgpgmeimportfromkeyserverjob.cpp
@@ -0,0 +1,82 @@
+/*
+ qgpgmeimportfromkeyserverjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeimportfromkeyserverjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "key.h"
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEImportFromKeyserverJob::QGpgMEImportFromKeyserverJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEImportFromKeyserverJob::~QGpgMEImportFromKeyserverJob() {}
+
+static QGpgMEImportFromKeyserverJob::result_type importfromkeyserver(Context *ctx, const std::vector<Key> &keys)
+{
+ const ImportResult res = ctx->importKeys(keys);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, log, ae);
+}
+
+Error QGpgMEImportFromKeyserverJob::start(const std::vector<Key> &keys)
+{
+ run(std::bind(&importfromkeyserver, std::placeholders::_1, keys));
+ return Error();
+}
+
+GpgME::ImportResult QGpgME::QGpgMEImportFromKeyserverJob::exec(const std::vector<Key> &keys)
+{
+ const result_type r = importfromkeyserver(context(), keys);
+ resultHook(r);
+ return mResult;
+}
+
+// PENDING(marc) implement showErrorDialog()
+
+void QGpgME::QGpgMEImportFromKeyserverJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+#include "qgpgmeimportfromkeyserverjob.moc"
diff --git a/lang/qt/src/qgpgmeimportfromkeyserverjob.h b/lang/qt/src/qgpgmeimportfromkeyserverjob.h
new file mode 100644
index 0000000..8c9f944
--- /dev/null
+++ b/lang/qt/src/qgpgmeimportfromkeyserverjob.h
@@ -0,0 +1,81 @@
+/*
+ qgpgmeimportfromkeyserverjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEIMPORTFROMKEYSERVERJOB_H__
+#define __QGPGME_QGPGMEIMPORTFROMKEYSERVERJOB_H__
+
+#include "importfromkeyserverjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "importresult.h"
+#else
+#include <gpgme++/importresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEImportFromKeyserverJob
+#ifdef Q_MOC_RUN
+ : public ImportFromKeyserverJob
+#else
+ : public _detail::ThreadedJobMixin<ImportFromKeyserverJob, std::tuple<GpgME::ImportResult, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEImportFromKeyserverJob(GpgME::Context *context);
+ ~QGpgMEImportFromKeyserverJob();
+
+ /* from ImportFromKeyserverJob */
+ GpgME::Error start(const std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+ /* from ImportFromKeyserverJob */
+ GpgME::ImportResult exec(const std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::ImportResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEIMPORTFROMKEYSERVERJOB_H__
diff --git a/lang/qt/src/qgpgmeimportjob.cpp b/lang/qt/src/qgpgmeimportjob.cpp
new file mode 100644
index 0000000..f125b12
--- /dev/null
+++ b/lang/qt/src/qgpgmeimportjob.cpp
@@ -0,0 +1,85 @@
+/*
+ qgpgmeimportjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeimportjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "key.h"
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEImportJob::QGpgMEImportJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEImportJob::~QGpgMEImportJob() {}
+
+static QGpgMEImportJob::result_type import_qba(Context *ctx, const QByteArray &certData)
+{
+ QGpgME::QByteArrayDataProvider dp(certData);
+ Data data(&dp);
+
+ const ImportResult res = ctx->importKeys(data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, log, ae);
+}
+
+Error QGpgMEImportJob::start(const QByteArray &certData)
+{
+ run(std::bind(&import_qba, std::placeholders::_1, certData));
+ return Error();
+}
+
+GpgME::ImportResult QGpgME::QGpgMEImportJob::exec(const QByteArray &keyData)
+{
+ const result_type r = import_qba(context(), keyData);
+ resultHook(r);
+ return mResult;
+}
+
+// PENDING(marc) implement showErrorDialog()
+
+void QGpgME::QGpgMEImportJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+#include "qgpgmeimportjob.moc"
diff --git a/lang/qt/src/qgpgmeimportjob.h b/lang/qt/src/qgpgmeimportjob.h
new file mode 100644
index 0000000..424cb50
--- /dev/null
+++ b/lang/qt/src/qgpgmeimportjob.h
@@ -0,0 +1,81 @@
+/*
+ qgpgmeimportjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEIMPORTJOB_H__
+#define __QGPGME_QGPGMEIMPORTJOB_H__
+
+#include "importjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "importresult.h"
+#else
+#include <gpgme++/importresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEImportJob
+#ifdef Q_MOC_RUN
+ : public ImportJob
+#else
+ : public _detail::ThreadedJobMixin<ImportJob, std::tuple<GpgME::ImportResult, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEImportJob(GpgME::Context *context);
+ ~QGpgMEImportJob();
+
+ /* from ImportJob */
+ GpgME::Error start(const QByteArray &keyData) Q_DECL_OVERRIDE;
+
+ /* from ImportJob */
+ GpgME::ImportResult exec(const QByteArray &keyData) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::ImportResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEIMPORTJOB_H__
diff --git a/lang/qt/src/qgpgmekeyformailboxjob.cpp b/lang/qt/src/qgpgmekeyformailboxjob.cpp
new file mode 100644
index 0000000..803d0e6
--- /dev/null
+++ b/lang/qt/src/qgpgmekeyformailboxjob.cpp
@@ -0,0 +1,138 @@
+/*
+ qgpgmekeyformailboxjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmekeyformailboxjob.h"
+#include "qgpgmekeylistjob.h"
+
+#include <QStringList>
+
+#include <tuple>
+
+using namespace GpgME;
+using namespace QGpgME;
+
+QGpgMEKeyForMailboxJob::QGpgMEKeyForMailboxJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEKeyForMailboxJob::~QGpgMEKeyForMailboxJob() {}
+
+static bool keyIsOk(const Key k)
+{
+ return !k.isExpired() && !k.isRevoked() && !k.isInvalid() && !k.isDisabled();
+}
+
+static bool uidIsOk(const UserID uid)
+{
+ return keyIsOk(uid.parent()) && !uid.isRevoked() && !uid.isInvalid();
+}
+
+static bool subkeyIsOk(const Subkey s)
+{
+ return !s.isRevoked() && !s.isInvalid() && !s.isDisabled();
+}
+
+static QGpgMEKeyForMailboxJob::result_type do_work(Context *ctx, const QString &mailbox, bool canEncrypt)
+{
+ /* Do a Keylisting. */
+ ctx->setKeyListMode(GpgME::Extern | GpgME::Local | GpgME::Signatures | GpgME::Validate);
+ std::vector<Key> keys;
+ QGpgMEKeyListJob *keylist = new QGpgMEKeyListJob(ctx);
+
+ KeyListResult result = keylist->exec(QStringList() << mailbox, false, keys);
+
+ if (result.error()) {
+ return std::make_tuple(result, Key(), UserID(), QString(), Error());
+ }
+
+ // This should ideally be decided by GnuPG and this Job changed
+ // to just call the according API in GpgME
+ // See: https://bugs.gnupg.org/gnupg/issue2359
+ Key keyC;
+ UserID uidC;
+ Q_FOREACH (const Key k, keys) {
+ if (canEncrypt && !k.canEncrypt()) {
+ continue;
+ }
+ /* First get the uid that matches the mailbox */
+ Q_FOREACH (const UserID u, k.userIDs()) {
+ if (QString::fromUtf8(u.email()).toLower() == mailbox.toLower()) {
+ if (uidC.isNull()) {
+ keyC = k;
+ uidC = u;
+ } else if ((!uidIsOk(uidC) && uidIsOk(u)) || uidC.validity() < u.validity()) {
+ /* Validity of the new key is better. */
+ uidC = u;
+ keyC = k;
+ } else if (uidC.validity() == u.validity() && uidIsOk(u)) {
+ /* Both are the same check which one is newer. */
+ time_t oldTime = 0;
+ Q_FOREACH (const Subkey s, keyC.subkeys()) {
+ if ((canEncrypt && s.canEncrypt()) && subkeyIsOk(s)) {
+ oldTime = s.creationTime();
+ }
+ }
+ time_t newTime = 0;
+ Q_FOREACH (const Subkey s, k.subkeys()) {
+ if ((canEncrypt && s.canEncrypt()) && subkeyIsOk(s)) {
+ newTime = s.creationTime();
+ }
+ }
+ if (newTime > oldTime) {
+ uidC = u;
+ keyC = k;
+ }
+ }
+ }
+ }
+ }
+ return std::make_tuple(result, keyC, uidC, QString(), Error());
+}
+
+Error QGpgMEKeyForMailboxJob::start(const QString &mailbox, bool canEncrypt)
+{
+ run(std::bind(&do_work, std::placeholders::_1, mailbox, canEncrypt));
+ return Error();
+}
+
+KeyListResult QGpgMEKeyForMailboxJob::exec(const QString &mailbox, bool canEncrypt, Key &key, UserID &uid)
+{
+ const result_type r = do_work(context(), mailbox, canEncrypt);
+ resultHook(r);
+ key = std::get<1>(r);
+ uid = std::get<2>(r);
+ return std::get<0>(r);
+}
+
+#include "qgpgmekeyformailboxjob.moc"
diff --git a/lang/qt/src/qgpgmekeyformailboxjob.h b/lang/qt/src/qgpgmekeyformailboxjob.h
new file mode 100644
index 0000000..8ac2c1f
--- /dev/null
+++ b/lang/qt/src/qgpgmekeyformailboxjob.h
@@ -0,0 +1,84 @@
+/*
+ qgpgmekeyformailboxjob.h
+
+ This file is part of libkleopatra, the KDE keymanagement library
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEKEYFORMAILBOXJOB_H__
+#define __QGPGME_QGPGMEKEYFORMAILBOXJOB_H__
+#include "keyformailboxjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "keylistresult.h"
+# include "key.h"
+#else
+# include <gpgme++/keylistresult.h>
+# include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEKeyForMailboxJob
+#ifdef Q_MOC_RUN
+ : public KeyForMailboxJob
+#else
+ : public _detail::ThreadedJobMixin<KeyForMailboxJob, std::tuple<GpgME::KeyListResult, GpgME::Key, GpgME::UserID, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEKeyForMailboxJob(GpgME::Context *context);
+ ~QGpgMEKeyForMailboxJob();
+
+ /**
+ Starts the operation. \a mailbox is the mailbox to
+ look for.
+
+ The result is the same as for the LocateKeysJob.
+
+ If \a canEncrypt is true, only keys that have a subkey for encryption
+ usage are returned. Use this if you need to select a
+ key for signing.
+ */
+ GpgME::Error start(const QString &mailbox, bool canEncrypt = true) Q_DECL_OVERRIDE;
+
+ GpgME::KeyListResult exec(const QString &mailbox, bool canEncrypt, GpgME::Key &key, GpgME::UserID &uid) Q_DECL_OVERRIDE;
+};
+
+}
+#endif
diff --git a/lang/qt/src/qgpgmekeygenerationjob.cpp b/lang/qt/src/qgpgmekeygenerationjob.cpp
new file mode 100644
index 0000000..cba6b76
--- /dev/null
+++ b/lang/qt/src/qgpgmekeygenerationjob.cpp
@@ -0,0 +1,71 @@
+/*
+ qgpgmekeygenerationjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmekeygenerationjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEKeyGenerationJob::QGpgMEKeyGenerationJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEKeyGenerationJob::~QGpgMEKeyGenerationJob() {}
+
+static QGpgMEKeyGenerationJob::result_type generate_key(Context *ctx, const QString &parameters)
+{
+ QGpgME::QByteArrayDataProvider dp;
+ Data data = ctx->protocol() == CMS ? Data(&dp) : Data(Data::null);
+ assert(data.isNull() == (ctx->protocol() != CMS));
+
+ const KeyGenerationResult res = ctx->generateKey(parameters.toUtf8().constData(), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, dp.data(), log, ae);
+}
+
+Error QGpgMEKeyGenerationJob::start(const QString &parameters)
+{
+ run(std::bind(&generate_key, std::placeholders::_1, parameters));
+ return Error();
+}
+#include "qgpgmekeygenerationjob.moc"
diff --git a/lang/qt/src/qgpgmekeygenerationjob.h b/lang/qt/src/qgpgmekeygenerationjob.h
new file mode 100644
index 0000000..808b714
--- /dev/null
+++ b/lang/qt/src/qgpgmekeygenerationjob.h
@@ -0,0 +1,72 @@
+/*
+ qgpgmekeygenerationjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEKEYGENERATIONJOB_H__
+#define __QGPGME_QGPGMEKEYGENERATIONJOB_H__
+
+#include "keygenerationjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "keygenerationresult.h"
+#else
+#include <gpgme++/keygenerationresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEKeyGenerationJob
+#ifdef Q_MOC_RUN
+ : public KeyGenerationJob
+#else
+ : public _detail::ThreadedJobMixin<KeyGenerationJob, std::tuple<GpgME::KeyGenerationResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+private Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEKeyGenerationJob(GpgME::Context *context);
+ ~QGpgMEKeyGenerationJob();
+
+ /* from KeygenerationJob */
+ GpgME::Error start(const QString &parameters) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEKEYGENERATIONJOB_H__
diff --git a/lang/qt/src/qgpgmekeylistjob.cpp b/lang/qt/src/qgpgmekeylistjob.cpp
new file mode 100644
index 0000000..1169c46
--- /dev/null
+++ b/lang/qt/src/qgpgmekeylistjob.cpp
@@ -0,0 +1,172 @@
+/*
+ qgpgmekeylistjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmekeylistjob.h"
+
+#include "key.h"
+#include "context.h"
+#include "keylistresult.h"
+#include <gpg-error.h>
+
+#include <QStringList>
+
+#include <algorithm>
+
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEKeyListJob::QGpgMEKeyListJob(Context *context)
+ : mixin_type(context),
+ mResult(), mSecretOnly(false)
+{
+ lateInitialization();
+}
+
+QGpgMEKeyListJob::~QGpgMEKeyListJob() {}
+
+static KeyListResult do_list_keys(Context *ctx, const QStringList &pats, std::vector<Key> &keys, bool secretOnly)
+{
+
+ const _detail::PatternConverter pc(pats);
+
+ if (const Error err = ctx->startKeyListing(pc.patterns(), secretOnly)) {
+ return KeyListResult(0, err);
+ }
+
+ Error err;
+ do {
+ keys.push_back(ctx->nextKey(err));
+ } while (!err);
+
+ keys.pop_back();
+
+ const KeyListResult result = ctx->endKeyListing();
+ ctx->cancelPendingOperation();
+ return result;
+}
+
+static QGpgMEKeyListJob::result_type list_keys(Context *ctx, QStringList pats, bool secretOnly)
+{
+ if (pats.size() < 2) {
+ std::vector<Key> keys;
+ const KeyListResult r = do_list_keys(ctx, pats, keys, secretOnly);
+ return std::make_tuple(r, keys, QString(), Error());
+ }
+
+ // The communication channel between gpgme and gpgsm is limited in
+ // the number of patterns that can be transported, but they won't
+ // say to how much, so we need to find out ourselves if we get a
+ // LINE_TOO_LONG error back...
+
+ // We could of course just feed them single patterns, and that would
+ // probably be easier, but the performance penalty would currently
+ // be noticeable.
+
+ unsigned int chunkSize = pats.size();
+retry:
+ std::vector<Key> keys;
+ keys.reserve(pats.size());
+ KeyListResult result;
+ do {
+ const KeyListResult this_result = do_list_keys(ctx, pats.mid(0, chunkSize), keys, secretOnly);
+ if (this_result.error().code() == GPG_ERR_LINE_TOO_LONG) {
+ // got LINE_TOO_LONG, try a smaller chunksize:
+ chunkSize /= 2;
+ if (chunkSize < 1)
+ // chunks smaller than one can't be -> return the error.
+ {
+ return std::make_tuple(this_result, keys, QString(), Error());
+ } else {
+ goto retry;
+ }
+ } else if (this_result.error().code() == GPG_ERR_EOF) {
+ // early end of keylisting (can happen when ~/.gnupg doesn't
+ // exist). Fakeing an empty result:
+ return std::make_tuple(KeyListResult(), std::vector<Key>(), QString(), Error());
+ }
+ // ok, that seemed to work...
+ result.mergeWith(this_result);
+ if (result.error().code()) {
+ break;
+ }
+ pats = pats.mid(chunkSize);
+ } while (!pats.empty());
+ return std::make_tuple(result, keys, QString(), Error());
+}
+
+Error QGpgMEKeyListJob::start(const QStringList &patterns, bool secretOnly)
+{
+ mSecretOnly = secretOnly;
+ run(std::bind(&list_keys, std::placeholders::_1, patterns, secretOnly));
+ return Error();
+}
+
+KeyListResult QGpgMEKeyListJob::exec(const QStringList &patterns, bool secretOnly, std::vector<Key> &keys)
+{
+ mSecretOnly = secretOnly;
+ const result_type r = list_keys(context(), patterns, secretOnly);
+ resultHook(r);
+ keys = std::get<1>(r);
+ return std::get<0>(r);
+}
+
+void QGpgMEKeyListJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+ Q_FOREACH (const Key &key, std::get<1>(tuple)) {
+ Q_EMIT nextKey(key);
+ }
+}
+
+void QGpgMEKeyListJob::addMode(KeyListMode mode)
+{
+ context()->addKeyListMode(mode);
+}
+#if 0
+void QGpgMEKeyListJob::showErrorDialog(QWidget *parent, const QString &caption) const
+{
+ if (!mResult.error() || mResult.error().isCanceled()) {
+ return;
+ }
+ const QString msg = i18n("<qt><p>An error occurred while fetching "
+ "the keys from the backend:</p>"
+ "<p><b>%1</b></p></qt>",
+ QString::fromLocal8Bit(mResult.error().asString()));
+ KMessageBox::error(parent, msg, caption);
+}
+#endif
+#include "qgpgmekeylistjob.moc"
diff --git a/lang/qt/src/qgpgmekeylistjob.h b/lang/qt/src/qgpgmekeylistjob.h
new file mode 100644
index 0000000..2d5406a
--- /dev/null
+++ b/lang/qt/src/qgpgmekeylistjob.h
@@ -0,0 +1,88 @@
+/*
+ qgpgmekeylistjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEKEYLISTJOB_H__
+#define __QGPGME_QGPGMEKEYLISTJOB_H__
+
+#include "keylistjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "keylistresult.h"
+#else
+#include <gpgme++/keylistresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEKeyListJob
+#ifdef Q_MOC_RUN
+ : public KeyListJob
+#else
+ : public _detail::ThreadedJobMixin<KeyListJob, std::tuple<GpgME::KeyListResult, std::vector<GpgME::Key>, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEKeyListJob(GpgME::Context *context);
+ ~QGpgMEKeyListJob();
+
+ /* from KeyListJob */
+ GpgME::Error start(const QStringList &patterns, bool secretOnly) Q_DECL_OVERRIDE;
+
+ /* from KeyListJob */
+ GpgME::KeyListResult exec(const QStringList &patterns, bool secretOnly, std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+ void addMode(GpgME::KeyListMode mode) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &result) Q_DECL_OVERRIDE;
+private:
+ GpgME::KeyListResult mResult;
+ bool mSecretOnly;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEKEYLISTJOB_H__
diff --git a/lang/qt/src/qgpgmelistallkeysjob.cpp b/lang/qt/src/qgpgmelistallkeysjob.cpp
new file mode 100644
index 0000000..fd8bfc3
--- /dev/null
+++ b/lang/qt/src/qgpgmelistallkeysjob.cpp
@@ -0,0 +1,168 @@
+/*
+ qgpgmelistallkeysjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmelistallkeysjob.h"
+
+#include "key.h"
+#include "context.h"
+#include "keylistresult.h"
+#include <gpg-error.h>
+
+#include <algorithm>
+
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEListAllKeysJob::QGpgMEListAllKeysJob(Context *context)
+ : mixin_type(context),
+ mResult()
+{
+ lateInitialization();
+}
+
+QGpgMEListAllKeysJob::~QGpgMEListAllKeysJob() {}
+
+static KeyListResult do_list_keys(Context *ctx, std::vector<Key> &keys, bool secretOnly)
+{
+
+ const char **pat = 0;
+ if (const Error err = ctx->startKeyListing(pat, secretOnly)) {
+ return KeyListResult(0, err);
+ }
+
+ Error err;
+ do {
+ keys.push_back(ctx->nextKey(err));
+ } while (!err);
+
+ keys.pop_back();
+
+ const KeyListResult result = ctx->endKeyListing();
+ ctx->cancelPendingOperation();
+ return result;
+}
+
+namespace
+{
+
+template <typename ForwardIterator, typename BinaryPredicate>
+ForwardIterator unique_by_merge(ForwardIterator first, ForwardIterator last, BinaryPredicate pred)
+{
+ first = std::adjacent_find(first, last, pred);
+ if (first == last) {
+ return last;
+ }
+
+ ForwardIterator dest = first;
+ dest->mergeWith(*++first);
+ while (++first != last)
+ if (pred(*dest, *first)) {
+ dest->mergeWith(*first);
+ } else {
+ *++dest = *first;
+ }
+ return ++dest;
+}
+
+}
+
+static void merge_keys(std::vector<Key> &merged, std::vector<Key> &pub, std::vector<Key> &sec)
+{
+ merged.reserve(pub.size() + sec.size());
+
+ std::merge(pub.begin(), pub.end(),
+ sec.begin(), sec.end(),
+ std::back_inserter(merged),
+ ByFingerprint<std::less>());
+
+ merged.erase(unique_by_merge(merged.begin(), merged.end(), ByFingerprint<std::equal_to>()),
+ merged.end());
+}
+
+static QGpgMEListAllKeysJob::result_type list_keys(Context *ctx, bool mergeKeys)
+{
+ std::vector<Key> pub, sec, merged;
+ KeyListResult r;
+
+ r.mergeWith(do_list_keys(ctx, pub, false));
+ std::sort(pub.begin(), pub.end(), ByFingerprint<std::less>());
+
+ r.mergeWith(do_list_keys(ctx, sec, true));
+ std::sort(sec.begin(), sec.end(), ByFingerprint<std::less>());
+
+ if (mergeKeys) {
+ merge_keys(merged, pub, sec);
+ } else {
+ merged.swap(pub);
+ }
+ return std::make_tuple(r, merged, sec, QString(), Error());
+}
+
+Error QGpgMEListAllKeysJob::start(bool mergeKeys)
+{
+ run(std::bind(&list_keys, std::placeholders::_1, mergeKeys));
+ return Error();
+}
+
+KeyListResult QGpgMEListAllKeysJob::exec(std::vector<Key> &pub, std::vector<Key> &sec, bool mergeKeys)
+{
+ const result_type r = list_keys(context(), mergeKeys);
+ resultHook(r);
+ pub = std::get<1>(r);
+ sec = std::get<2>(r);
+ return std::get<0>(r);
+}
+
+void QGpgMEListAllKeysJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+
+#if 0
+void QGpgMEListAllKeysJob::showErrorDialog(QWidget *parent, const QString &caption) const
+{
+ if (!mResult.error() || mResult.error().isCanceled()) {
+ return;
+ }
+ const QString msg = i18n("<qt><p>An error occurred while fetching "
+ "the keys from the backend:</p>"
+ "<p><b>%1</b></p></qt>",
+ QString::fromLocal8Bit(mResult.error().asString()));
+ KMessageBox::error(parent, msg, caption);
+}
+#endif
+#include "qgpgmelistallkeysjob.moc"
diff --git a/lang/qt/src/qgpgmelistallkeysjob.h b/lang/qt/src/qgpgmelistallkeysjob.h
new file mode 100644
index 0000000..1fc69d4
--- /dev/null
+++ b/lang/qt/src/qgpgmelistallkeysjob.h
@@ -0,0 +1,86 @@
+/*
+ qgpgmelistallkeysjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMELISTALLKEYSJOB_H__
+#define __QGPGME_QGPGMELISTALLKEYSJOB_H__
+
+#include "listallkeysjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "keylistresult.h"
+#else
+#include <gpgme++/keylistresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEListAllKeysJob
+#ifdef Q_MOC_RUN
+ : public ListAllKeysJob
+#else
+ : public _detail::ThreadedJobMixin<ListAllKeysJob, std::tuple<GpgME::KeyListResult, std::vector<GpgME::Key>, std::vector<GpgME::Key>, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEListAllKeysJob(GpgME::Context *context);
+ ~QGpgMEListAllKeysJob();
+
+ /* from ListAllKeysJob */
+ GpgME::Error start(bool mergeKeys) Q_DECL_OVERRIDE;
+
+ /* from ListAllKeysJob */
+ GpgME::KeyListResult exec(std::vector<GpgME::Key> &pub, std::vector<GpgME::Key> &sec, bool mergeKeys) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &result) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::KeyListResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMELISTALLKEYSJOB_H__
diff --git a/lang/qt/src/qgpgmenewcryptoconfig.cpp b/lang/qt/src/qgpgmenewcryptoconfig.cpp
new file mode 100644
index 0000000..7303f10
--- /dev/null
+++ b/lang/qt/src/qgpgmenewcryptoconfig.cpp
@@ -0,0 +1,738 @@
+/*
+ qgpgmenewcryptoconfig.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmenewcryptoconfig.h"
+
+#include <QDebug>
+#include "gpgme_backend_debug.h"
+
+#include <QFile>
+
+#include "global.h"
+#include "error.h"
+
+
+#include <sstream>
+#include <string>
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace GpgME::Configuration;
+
+namespace
+{
+struct Select1St {
+ template <typename U, typename V>
+ const U &operator()(const std::pair<U, V> &p) const
+ {
+ return p.first;
+ }
+ template <typename U, typename V>
+ const U &operator()(const QPair<U, V> &p) const
+ {
+ return p.first;
+ }
+};
+}
+
+// Just for the Q_ASSERT in the dtor. Not thread-safe, but who would
+// have 2 threads talking to gpgconf anyway? :)
+static bool s_duringClear = false;
+
+QGpgMENewCryptoConfig::QGpgMENewCryptoConfig()
+ : m_parsed(false)
+{
+}
+
+QGpgMENewCryptoConfig::~QGpgMENewCryptoConfig()
+{
+ clear();
+}
+
+void QGpgMENewCryptoConfig::reloadConfiguration(bool showErrors)
+{
+ clear();
+
+ Error error;
+ const std::vector<Component> components = Component::load(error);
+#ifndef NDEBUG
+ {
+ std::stringstream ss;
+ ss << "error: " << error
+ << "components:\n";
+ std::copy(components.begin(), components.end(),
+ std::ostream_iterator<Component>(ss, "\n"));
+ qCDebug(GPGPME_BACKEND_LOG) << ss.str().c_str();
+ }
+#endif
+#if 0
+ TODO port?
+ if (error && showErrors) {
+ const QString wmsg = i18n("<qt>Failed to execute gpgconf:<p>%1</p></qt>", QString::fromLocal8Bit(error.asString()));
+ qCWarning(GPGPME_BACKEND_LOG) << wmsg; // to see it from test_cryptoconfig.cpp
+ KMessageBox::error(0, wmsg);
+ }
+#endif
+ Q_FOREACH(const Component & c, components) {
+ const std::shared_ptr<QGpgMENewCryptoConfigComponent> comp(new QGpgMENewCryptoConfigComponent);
+ comp->setComponent(c);
+ m_componentsByName[ comp->name() ] = comp;
+ }
+ m_parsed = true;
+}
+
+QStringList QGpgMENewCryptoConfig::componentList() const
+{
+ if (!m_parsed) {
+ const_cast<QGpgMENewCryptoConfig *>(this)->reloadConfiguration(true);
+ }
+ QStringList result;
+ std::transform(m_componentsByName.begin(), m_componentsByName.end(),
+ std::back_inserter(result),
+ mem_fn(&QGpgMENewCryptoConfigComponent::name));
+ return result;
+}
+
+QGpgMENewCryptoConfigComponent *QGpgMENewCryptoConfig::component(const QString &name) const
+{
+ if (!m_parsed) {
+ const_cast<QGpgMENewCryptoConfig *>(this)->reloadConfiguration(false);
+ }
+ return m_componentsByName.value(name).get();
+}
+
+void QGpgMENewCryptoConfig::sync(bool runtime)
+{
+ Q_FOREACH(const std::shared_ptr<QGpgMENewCryptoConfigComponent> &c, m_componentsByName)
+ c->sync(runtime);
+}
+
+void QGpgMENewCryptoConfig::clear()
+{
+ s_duringClear = true;
+ m_componentsByName.clear();
+ s_duringClear = false;
+ m_parsed = false; // next call to componentList/component will need to run gpgconf again
+}
+
+////
+
+QGpgMENewCryptoConfigComponent::QGpgMENewCryptoConfigComponent()
+ : CryptoConfigComponent(),
+ m_component()
+{
+
+}
+
+void QGpgMENewCryptoConfigComponent::setComponent(const Component &component)
+{
+ m_component = component;
+ m_groupsByName.clear();
+
+ std::shared_ptr<QGpgMENewCryptoConfigGroup> group;
+
+ const std::vector<Option> options = m_component.options();
+ Q_FOREACH(const Option & o, options)
+ if (o.flags() & Group) {
+ if (group) {
+ m_groupsByName[group->name()] = group;
+ }
+ group.reset(new QGpgMENewCryptoConfigGroup(shared_from_this(), o));
+ } else if (group) {
+ const std::shared_ptr<QGpgMENewCryptoConfigEntry> entry(new QGpgMENewCryptoConfigEntry(group, o));
+ const QString name = entry->name();
+ group->m_entryNames.push_back(name);
+ group->m_entriesByName[name] = entry;
+ } else {
+ qCWarning(GPGPME_BACKEND_LOG) << "found no group for entry" << o.name() << "of component" << name();
+ }
+ if (group) {
+ m_groupsByName[group->name()] = group;
+ }
+
+}
+
+QGpgMENewCryptoConfigComponent::~QGpgMENewCryptoConfigComponent() {}
+
+QString QGpgMENewCryptoConfigComponent::name() const
+{
+ return QString::fromUtf8(m_component.name());
+}
+
+QString QGpgMENewCryptoConfigComponent::description() const
+{
+ return QString::fromUtf8(m_component.description());
+}
+
+QStringList QGpgMENewCryptoConfigComponent::groupList() const
+{
+ QStringList result;
+ result.reserve(m_groupsByName.size());
+ std::transform(m_groupsByName.begin(), m_groupsByName.end(),
+ std::back_inserter(result),
+ std::mem_fn(&QGpgMENewCryptoConfigGroup::name));
+ return result;
+}
+
+QGpgMENewCryptoConfigGroup *QGpgMENewCryptoConfigComponent::group(const QString &name) const
+{
+ return m_groupsByName.value(name).get();
+}
+
+void QGpgMENewCryptoConfigComponent::sync(bool runtime)
+{
+ Q_UNUSED(runtime)
+ // ### how to pass --runtime to gpgconf? -> marcus: not yet supported (2010-11-20)
+ if (const Error err = m_component.save()) {
+#if 0
+ TODO port
+ const QString wmsg = i18n("Error from gpgconf while saving configuration: %1", QString::fromLocal8Bit(err.asString()));
+ qCWarning(GPGPME_BACKEND_LOG) << ":" << wmsg;
+ KMessageBox::error(0, wmsg);
+#endif
+ }
+ // ### unset dirty state again
+}
+
+////
+
+QGpgMENewCryptoConfigGroup::QGpgMENewCryptoConfigGroup(const std::shared_ptr<QGpgMENewCryptoConfigComponent> &comp, const Option &option)
+ : CryptoConfigGroup(),
+ m_component(comp),
+ m_option(option)
+{
+}
+
+QGpgMENewCryptoConfigGroup::~QGpgMENewCryptoConfigGroup() {}
+
+QString QGpgMENewCryptoConfigGroup::name() const
+{
+ return QString::fromUtf8(m_option.name());
+}
+
+QString QGpgMENewCryptoConfigGroup::description() const
+{
+ return QString::fromUtf8(m_option.description());
+}
+
+QString QGpgMENewCryptoConfigGroup::path() const
+{
+ if (const std::shared_ptr<QGpgMENewCryptoConfigComponent> c = m_component.lock()) {
+ return c->name() + QLatin1Char('/') + name();
+ } else {
+ return QString();
+ }
+}
+
+CryptoConfigEntry::Level QGpgMENewCryptoConfigGroup::level() const
+{
+ // two casts to make SunCC happy:
+ return static_cast<CryptoConfigEntry::Level>(static_cast<unsigned int>(m_option.level()));
+}
+
+QStringList QGpgMENewCryptoConfigGroup::entryList() const
+{
+ return m_entryNames;
+}
+
+QGpgMENewCryptoConfigEntry *QGpgMENewCryptoConfigGroup::entry(const QString &name) const
+{
+ return m_entriesByName.value(name).get();
+}
+
+static QString urlpart_encode(const QString &str)
+{
+ QString enc(str);
+ enc.replace(QLatin1Char('%'), QStringLiteral("%25")); // first!
+ enc.replace(QLatin1Char(':'), QStringLiteral("%3a"));
+ //qCDebug(GPGPME_BACKEND_LOG) <<" urlpart_encode:" << str <<" ->" << enc;
+ return enc;
+}
+
+static QString urlpart_decode(const QString &str)
+{
+ return QUrl::fromPercentEncoding(str.toLatin1());
+}
+
+// gpgconf arg type number -> NewCryptoConfigEntry arg type enum mapping
+static QGpgME::CryptoConfigEntry::ArgType knownArgType(int argType, bool &ok)
+{
+ ok = true;
+ switch (argType) {
+ case 0: // none
+ return QGpgME::CryptoConfigEntry::ArgType_None;
+ case 1: // string
+ return QGpgME::CryptoConfigEntry::ArgType_String;
+ case 2: // int32
+ return QGpgME::CryptoConfigEntry::ArgType_Int;
+ case 3: // uint32
+ return QGpgME::CryptoConfigEntry::ArgType_UInt;
+ case 32: // pathname
+ return QGpgME::CryptoConfigEntry::ArgType_Path;
+ case 33: // ldap server
+ return QGpgME::CryptoConfigEntry::ArgType_LDAPURL;
+ default:
+ ok = false;
+ return QGpgME::CryptoConfigEntry::ArgType_None;
+ }
+}
+
+QGpgMENewCryptoConfigEntry::QGpgMENewCryptoConfigEntry(const std::shared_ptr<QGpgMENewCryptoConfigGroup> &group, const Option &option)
+ : m_group(group), m_option(option)
+{
+}
+
+#if 0
+QVariant QGpgMENewCryptoConfigEntry::stringToValue(const QString &str, bool unescape) const
+{
+ const bool isString = isStringType();
+
+ if (isList()) {
+ if (argType() == ArgType_None) {
+ bool ok = true;
+ const QVariant v = str.isEmpty() ? 0U : str.toUInt(&ok);
+ if (!ok) {
+ qCWarning(GPGPME_BACKEND_LOG) << "list-of-none should have an unsigned int as value:" << str;
+ }
+ return v;
+ }
+ QList<QVariant> lst;
+ QStringList items = str.split(',', QString::SkipEmptyParts);
+ for (QStringList::const_iterator valit = items.constBegin(); valit != items.constEnd(); ++valit) {
+ QString val = *valit;
+ if (isString) {
+ if (val.isEmpty()) {
+ lst << QVariant(QString());
+ continue;
+ } else if (unescape) {
+ if (val[0] != '"') { // see README.gpgconf
+ qCWarning(GPGPME_BACKEND_LOG) << "String value should start with '\"' :" << val;
+ }
+ val = val.mid(1);
+ }
+ }
+ lst << QVariant(unescape ? gpgconf_unescape(val) : val);
+ }
+ return lst;
+ } else { // not a list
+ QString val(str);
+ if (isString) {
+ if (val.isEmpty()) {
+ return QVariant(QString()); // not set [ok with lists too?]
+ } else if (unescape) {
+ if (val[0] != '"') { // see README.gpgconf
+ qCWarning(GPGPME_BACKEND_LOG) << "String value should start with '\"' :" << val;
+ }
+ val = val.mid(1);
+ }
+ }
+ return QVariant(unescape ? gpgconf_unescape(val) : val);
+ }
+}
+#endif
+
+QGpgMENewCryptoConfigEntry::~QGpgMENewCryptoConfigEntry()
+{
+#ifndef NDEBUG
+ if (!s_duringClear && m_option.dirty())
+ qCWarning(GPGPME_BACKEND_LOG) << "Deleting a QGpgMENewCryptoConfigEntry that was modified (" << m_option.description() << ")"
+ << "You forgot to call sync() (to commit) or clear() (to discard)";
+#endif
+}
+
+QString QGpgMENewCryptoConfigEntry::name() const
+{
+ return QString::fromUtf8(m_option.name());
+}
+
+QString QGpgMENewCryptoConfigEntry::description() const
+{
+ return QString::fromUtf8(m_option.description());
+}
+
+QString QGpgMENewCryptoConfigEntry::path() const
+{
+ if (const std::shared_ptr<QGpgMENewCryptoConfigGroup> g = m_group.lock()) {
+ return g->path() + QLatin1Char('/') + name();
+ } else {
+ return QString();
+ }
+}
+
+bool QGpgMENewCryptoConfigEntry::isOptional() const
+{
+ return m_option.flags() & Optional;
+}
+
+bool QGpgMENewCryptoConfigEntry::isReadOnly() const
+{
+ return m_option.flags() & NoChange;
+}
+
+bool QGpgMENewCryptoConfigEntry::isList() const
+{
+ return m_option.flags() & List;
+}
+
+bool QGpgMENewCryptoConfigEntry::isRuntime() const
+{
+ return m_option.flags() & Runtime;
+}
+
+CryptoConfigEntry::Level QGpgMENewCryptoConfigEntry::level() const
+{
+ // two casts to make SunCC happy:
+ return static_cast<Level>(static_cast<unsigned int>(m_option.level()));
+}
+
+CryptoConfigEntry::ArgType QGpgMENewCryptoConfigEntry::argType() const
+{
+ bool ok = false;
+ const ArgType type = knownArgType(m_option.type(), ok);
+ if (ok) {
+ return type;
+ } else {
+ return knownArgType(m_option.alternateType(), ok);
+ }
+}
+
+bool QGpgMENewCryptoConfigEntry::isSet() const
+{
+ return m_option.set();
+}
+
+bool QGpgMENewCryptoConfigEntry::boolValue() const
+{
+ Q_ASSERT(m_option.alternateType() == NoType);
+ Q_ASSERT(!isList());
+ return m_option.currentValue().boolValue();
+}
+
+QString QGpgMENewCryptoConfigEntry::stringValue() const
+{
+ //return toString( false );
+ Q_ASSERT(m_option.alternateType() == StringType);
+ Q_ASSERT(!isList());
+ return QString::fromUtf8(m_option.currentValue().stringValue());
+}
+
+int QGpgMENewCryptoConfigEntry::intValue() const
+{
+ Q_ASSERT(m_option.alternateType() == IntegerType);
+ Q_ASSERT(!isList());
+ return m_option.currentValue().intValue();
+}
+
+unsigned int QGpgMENewCryptoConfigEntry::uintValue() const
+{
+ Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
+ Q_ASSERT(!isList());
+ return m_option.currentValue().uintValue();
+}
+
+static QUrl parseURL(int mRealArgType, const QString &str)
+{
+ if (mRealArgType == 33) { // LDAP server
+ // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
+ QStringList items = str.split(QLatin1Char(':'));
+ if (items.count() == 5) {
+ QStringList::const_iterator it = items.constBegin();
+ QUrl url;
+ url.setScheme(QStringLiteral("ldap"));
+ url.setHost(urlpart_decode(*it++));
+
+ bool ok;
+ const int port = (*it++).toInt(&ok);
+ if (ok) {
+ url.setPort(port);
+ } else if (!it->isEmpty()) {
+ qCWarning(GPGPME_BACKEND_LOG) << "parseURL: malformed LDAP server port, ignoring: \"" << *it << "\"";
+ }
+
+ const QString userName = urlpart_decode(*it++);
+ if (!userName.isEmpty()) {
+ url.setUserName(userName);
+ }
+ const QString passWord = urlpart_decode(*it++);
+ if (!passWord.isEmpty()) {
+ url.setPassword(passWord);
+ }
+ url.setQuery(urlpart_decode(*it));
+ return url;
+ } else {
+ qCWarning(GPGPME_BACKEND_LOG) << "parseURL: malformed LDAP server:" << str;
+ }
+ }
+ // other URLs : assume wellformed URL syntax.
+ return QUrl(str);
+}
+
+// The opposite of parseURL
+static QString splitURL(int mRealArgType, const QUrl &url)
+{
+ if (mRealArgType == 33) { // LDAP server
+ // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
+ Q_ASSERT(url.scheme() == QLatin1String("ldap"));
+ return urlpart_encode(url.host()) + QLatin1Char(':') +
+ (url.port() != -1 ? QString::number(url.port()) : QString()) + QLatin1Char(':') + // -1 is used for default ports, omit
+ urlpart_encode(url.userName()) + QLatin1Char(':') +
+ urlpart_encode(url.password()) + QLatin1Char(':') +
+ urlpart_encode(url.query());
+ }
+ return url.path();
+}
+
+QUrl QGpgMENewCryptoConfigEntry::urlValue() const
+{
+ const Type type = m_option.type();
+ Q_ASSERT(type == FilenameType || type == LdapServerType);
+ Q_ASSERT(!isList());
+ if (type == FilenameType) {
+ QUrl url;
+ url.setPath(QFile::decodeName(m_option.currentValue().stringValue()));
+ return url;
+ }
+ return parseURL(type, stringValue());
+}
+
+unsigned int QGpgMENewCryptoConfigEntry::numberOfTimesSet() const
+{
+ Q_ASSERT(m_option.alternateType() == NoType);
+ Q_ASSERT(isList());
+ return m_option.currentValue().uintValue();
+}
+
+std::vector<int> QGpgMENewCryptoConfigEntry::intValueList() const
+{
+ Q_ASSERT(m_option.alternateType() == IntegerType);
+ Q_ASSERT(isList());
+ return m_option.currentValue().intValues();
+}
+
+std::vector<unsigned int> QGpgMENewCryptoConfigEntry::uintValueList() const
+{
+ Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
+ Q_ASSERT(isList());
+ return m_option.currentValue().uintValues();
+}
+
+QList<QUrl> QGpgMENewCryptoConfigEntry::urlValueList() const
+{
+ const Type type = m_option.type();
+ Q_ASSERT(type == FilenameType || type == LdapServerType);
+ Q_ASSERT(isList());
+ const Argument arg = m_option.currentValue();
+ const std::vector<const char *> values = arg.stringValues();
+ QList<QUrl> ret;
+ Q_FOREACH(const char *value, values)
+ if (type == FilenameType) {
+ QUrl url;
+ url.setPath(QFile::decodeName(value));
+ ret << url;
+ } else {
+ ret << parseURL(type, QString::fromUtf8(value));
+ }
+ return ret;
+}
+
+void QGpgMENewCryptoConfigEntry::resetToDefault()
+{
+ m_option.resetToDefaultValue();
+}
+
+void QGpgMENewCryptoConfigEntry::setBoolValue(bool b)
+{
+ Q_ASSERT(m_option.alternateType() == NoType);
+ Q_ASSERT(!isList());
+ // A "no arg" option is either set or not set.
+ // Being set means createNoneArgument(), being unset means resetToDefault()
+ m_option.setNewValue(m_option.createNoneArgument(b));
+}
+
+void QGpgMENewCryptoConfigEntry::setStringValue(const QString &str)
+{
+ Q_ASSERT(m_option.alternateType() == StringType);
+ Q_ASSERT(!isList());
+ const Type type = m_option.type();
+ // When setting a string to empty (and there's no default), we need to act like resetToDefault
+ // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
+ // "gpgconf: argument required for option ocsp-responder"
+ if (str.isEmpty() && !isOptional()) {
+ m_option.resetToDefaultValue();
+ } else if (type == FilenameType) {
+ m_option.setNewValue(m_option.createStringArgument(QFile::encodeName(str).constData()));
+ } else {
+ m_option.setNewValue(m_option.createStringArgument(str.toUtf8().constData()));
+ }
+}
+
+void QGpgMENewCryptoConfigEntry::setIntValue(int i)
+{
+ Q_ASSERT(m_option.alternateType() == IntegerType);
+ Q_ASSERT(!isList());
+ m_option.setNewValue(m_option.createIntArgument(i));
+}
+
+void QGpgMENewCryptoConfigEntry::setUIntValue(unsigned int i)
+{
+ Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
+ Q_ASSERT(!isList());
+ m_option.setNewValue(m_option.createUIntArgument(i));
+}
+
+void QGpgMENewCryptoConfigEntry::setURLValue(const QUrl &url)
+{
+ const Type type = m_option.type();
+ Q_ASSERT(type == FilenameType || type == LdapServerType);
+ Q_ASSERT(!isList());
+ const QString str = splitURL(type, url);
+ // cf. setStringValue()
+ if (str.isEmpty() && !isOptional()) {
+ m_option.resetToDefaultValue();
+ } else if (type == FilenameType) {
+ m_option.setNewValue(m_option.createStringArgument(QFile::encodeName(str).constData()));
+ } else {
+ m_option.setNewValue(m_option.createStringArgument(str.toUtf8().constData()));
+ }
+}
+
+void QGpgMENewCryptoConfigEntry::setNumberOfTimesSet(unsigned int i)
+{
+ Q_ASSERT(m_option.alternateType() == NoType);
+ Q_ASSERT(isList());
+ m_option.setNewValue(m_option.createNoneListArgument(i));
+}
+
+void QGpgMENewCryptoConfigEntry::setIntValueList(const std::vector<int> &lst)
+{
+ Q_ASSERT(m_option.alternateType() == IntegerType);
+ Q_ASSERT(isList());
+ m_option.setNewValue(m_option.createIntListArgument(lst));
+}
+
+void QGpgMENewCryptoConfigEntry::setUIntValueList(const std::vector<unsigned int> &lst)
+{
+ Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
+ Q_ASSERT(isList());
+ m_option.setNewValue(m_option.createUIntListArgument(lst));
+}
+
+void QGpgMENewCryptoConfigEntry::setURLValueList(const QList<QUrl> &urls)
+{
+ const Type type = m_option.type();
+ Q_ASSERT(m_option.alternateType() == StringType);
+ Q_ASSERT(isList());
+ std::vector<std::string> values;
+ values.reserve(urls.size());
+ Q_FOREACH (const QUrl &url, urls)
+ if (type == FilenameType) {
+ values.push_back(QFile::encodeName(url.path()).constData());
+ } else {
+ values.push_back(splitURL(type, url).toUtf8().constData());
+ }
+ m_option.setNewValue(m_option.createStringListArgument(values));
+}
+
+bool QGpgMENewCryptoConfigEntry::isDirty() const
+{
+ return m_option.dirty();
+}
+
+#if 0
+QString QGpgMENewCryptoConfigEntry::toString(bool escape) const
+{
+ // Basically the opposite of stringToValue
+ if (isStringType()) {
+ if (mValue.isNull()) {
+ return QString();
+ } else if (isList()) { // string list
+ QStringList lst = mValue.toStringList();
+ if (escape) {
+ for (QStringList::iterator it = lst.begin(); it != lst.end(); ++it) {
+ if (!(*it).isNull()) {
+ *it = gpgconf_escape(*it).prepend("\"");
+ }
+ }
+ }
+ QString res = lst.join(",");
+ //qCDebug(GPGPME_BACKEND_LOG) <<"toString:" << res;
+ return res;
+ } else { // normal string
+ QString res = mValue.toString();
+ if (escape) {
+ res = gpgconf_escape(res).prepend("\"");
+ }
+ return res;
+ }
+ }
+ if (!isList()) { // non-list non-string
+ if (mArgType == ArgType_None) {
+ return mValue.toBool() ? QString::fromLatin1("1") : QString();
+ } else { // some int
+ Q_ASSERT(mArgType == ArgType_Int || mArgType == ArgType_UInt);
+ return mValue.toString(); // int to string conversion
+ }
+ }
+
+ // Lists (of other types than strings)
+ if (mArgType == ArgType_None) {
+ return QString::number(numberOfTimesSet());
+ }
+ QStringList ret;
+ QList<QVariant> lst = mValue.toList();
+ for (QList<QVariant>::const_iterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
+ ret << (*it).toString(); // QVariant does the conversion
+ }
+ return ret.join(",");
+}
+
+QString QGpgMENewCryptoConfigEntry::outputString() const
+{
+ Q_ASSERT(mSet);
+ return toString(true);
+}
+
+bool QGpgMENewCryptoConfigEntry::isStringType() const
+{
+ return (mArgType == QGpgME::NewCryptoConfigEntry::ArgType_String
+ || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_Path
+ || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_URL
+ || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_LDAPURL);
+}
+
+void QGpgMENewCryptoConfigEntry::setDirty(bool b)
+{
+ mDirty = b;
+}
+#endif
diff --git a/lang/qt/src/qgpgmenewcryptoconfig.h b/lang/qt/src/qgpgmenewcryptoconfig.h
new file mode 100644
index 0000000..81b4cb4
--- /dev/null
+++ b/lang/qt/src/qgpgmenewcryptoconfig.h
@@ -0,0 +1,189 @@
+/*
+ qgpgmenewcryptoconfig.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2010 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef QGPGME_QGPGMENEWCRYPTOCONFIG_H
+#define QGPGME_QGPGMENEWCRYPTOCONFIG_H
+
+#include "qgpgme_export.h"
+#include "cryptoconfig.h"
+
+#include <QHash>
+#include <QStringList>
+#include <QVariant>
+
+#ifdef BUILDING_QGPGME
+# include "configuration.h"
+#else
+# include <gpgme++/configuration.h>
+#endif
+
+
+#include <vector>
+#include <utility>
+
+class QGpgMENewCryptoConfig;
+class QGpgMENewCryptoConfigComponent;
+class QGpgMENewCryptoConfigGroup;
+class QGpgMENewCryptoConfigEntry;
+
+class QGpgMENewCryptoConfigEntry : public QGpgME::CryptoConfigEntry
+{
+public:
+ QGpgMENewCryptoConfigEntry(const std::shared_ptr<QGpgMENewCryptoConfigGroup> &group, const GpgME::Configuration::Option &option);
+ ~QGpgMENewCryptoConfigEntry();
+
+ QString name() const Q_DECL_OVERRIDE;
+ QString description() const Q_DECL_OVERRIDE;
+ QString path() const Q_DECL_OVERRIDE;
+ bool isOptional() const Q_DECL_OVERRIDE;
+ bool isReadOnly() const Q_DECL_OVERRIDE;
+ bool isList() const Q_DECL_OVERRIDE;
+ bool isRuntime() const Q_DECL_OVERRIDE;
+ Level level() const Q_DECL_OVERRIDE;
+ ArgType argType() const Q_DECL_OVERRIDE;
+ bool isSet() const Q_DECL_OVERRIDE;
+ bool boolValue() const Q_DECL_OVERRIDE;
+ QString stringValue() const Q_DECL_OVERRIDE;
+ int intValue() const Q_DECL_OVERRIDE;
+ unsigned int uintValue() const Q_DECL_OVERRIDE;
+ QUrl urlValue() const Q_DECL_OVERRIDE;
+ unsigned int numberOfTimesSet() const Q_DECL_OVERRIDE;
+ std::vector<int> intValueList() const Q_DECL_OVERRIDE;
+ std::vector<unsigned int> uintValueList() const Q_DECL_OVERRIDE;
+ QList<QUrl> urlValueList() const Q_DECL_OVERRIDE;
+ void resetToDefault() Q_DECL_OVERRIDE;
+ void setBoolValue(bool) Q_DECL_OVERRIDE;
+ void setStringValue(const QString &) Q_DECL_OVERRIDE;
+ void setIntValue(int) Q_DECL_OVERRIDE;
+ void setUIntValue(unsigned int) Q_DECL_OVERRIDE;
+ void setURLValue(const QUrl &) Q_DECL_OVERRIDE;
+ void setNumberOfTimesSet(unsigned int) Q_DECL_OVERRIDE;
+ void setIntValueList(const std::vector<int> &) Q_DECL_OVERRIDE;
+ void setUIntValueList(const std::vector<unsigned int> &) Q_DECL_OVERRIDE;
+ void setURLValueList(const QList<QUrl> &) Q_DECL_OVERRIDE;
+ bool isDirty() const Q_DECL_OVERRIDE;
+
+#if 0
+ void setDirty(bool b);
+ QString outputString() const;
+
+protected:
+ bool isStringType() const;
+ QVariant stringToValue(const QString &value, bool unescape) const;
+ QString toString(bool escape) const;
+#endif
+private:
+ std::weak_ptr<QGpgMENewCryptoConfigGroup> m_group;
+ GpgME::Configuration::Option m_option;
+};
+
+class QGpgMENewCryptoConfigGroup : public QGpgME::CryptoConfigGroup
+{
+public:
+ QGpgMENewCryptoConfigGroup(const std::shared_ptr<QGpgMENewCryptoConfigComponent> &parent, const GpgME::Configuration::Option &option);
+ ~QGpgMENewCryptoConfigGroup();
+
+ QString name() const Q_DECL_OVERRIDE;
+ QString iconName() const Q_DECL_OVERRIDE
+ {
+ return QString();
+ }
+ QString description() const Q_DECL_OVERRIDE;
+ QString path() const Q_DECL_OVERRIDE;
+ QGpgME::CryptoConfigEntry::Level level() const Q_DECL_OVERRIDE;
+ QStringList entryList() const Q_DECL_OVERRIDE;
+ QGpgMENewCryptoConfigEntry *entry(const QString &name) const Q_DECL_OVERRIDE;
+
+private:
+ friend class QGpgMENewCryptoConfigComponent; // it adds the entries
+ std::weak_ptr<QGpgMENewCryptoConfigComponent> m_component;
+ GpgME::Configuration::Option m_option;
+ QStringList m_entryNames;
+ QHash< QString, std::shared_ptr<QGpgMENewCryptoConfigEntry> > m_entriesByName;
+};
+
+/// For docu, see kleo/cryptoconfig.h
+class QGpgMENewCryptoConfigComponent : public QGpgME::CryptoConfigComponent, public std::enable_shared_from_this<QGpgMENewCryptoConfigComponent>
+{
+public:
+ QGpgMENewCryptoConfigComponent();
+ ~QGpgMENewCryptoConfigComponent();
+
+ void setComponent(const GpgME::Configuration::Component &component);
+
+ QString name() const Q_DECL_OVERRIDE;
+ QString iconName() const Q_DECL_OVERRIDE
+ {
+ return name();
+ }
+ QString description() const Q_DECL_OVERRIDE;
+ QStringList groupList() const Q_DECL_OVERRIDE;
+ QGpgMENewCryptoConfigGroup *group(const QString &name) const Q_DECL_OVERRIDE;
+
+ void sync(bool runtime);
+
+private:
+ GpgME::Configuration::Component m_component;
+ QHash< QString, std::shared_ptr<QGpgMENewCryptoConfigGroup> > m_groupsByName;
+};
+
+/**
+ * CryptoConfig implementation around the gpgconf command-line tool
+ * For method docu, see kleo/cryptoconfig.h
+ */
+class QGPGME_EXPORT QGpgMENewCryptoConfig : public QGpgME::CryptoConfig
+{
+public:
+ /**
+ * Constructor
+ */
+ QGpgMENewCryptoConfig();
+ ~QGpgMENewCryptoConfig();
+
+ QStringList componentList() const Q_DECL_OVERRIDE;
+
+ QGpgMENewCryptoConfigComponent *component(const QString &name) const Q_DECL_OVERRIDE;
+
+ void clear() Q_DECL_OVERRIDE;
+ void sync(bool runtime) Q_DECL_OVERRIDE;
+
+private:
+ /// @param showErrors if true, a messagebox will be shown if e.g. gpgconf wasn't found
+ void reloadConfiguration(bool showErrors);
+
+private:
+ QHash< QString, std::shared_ptr<QGpgMENewCryptoConfigComponent> > m_componentsByName;
+ bool m_parsed;
+};
+
+#endif /* QGPGME_QGPGMENEWCRYPTOCONFIG_H */
diff --git a/lang/qt/src/qgpgmerefreshkeysjob.cpp b/lang/qt/src/qgpgmerefreshkeysjob.cpp
new file mode 100644
index 0000000..3d221f6
--- /dev/null
+++ b/lang/qt/src/qgpgmerefreshkeysjob.cpp
@@ -0,0 +1,225 @@
+/*
+ qgpgmerefreshkeysjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klar�vdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#define MAX_CMD_LENGTH 32768
+
+#include "qgpgmerefreshkeysjob.h"
+
+#include <QDebug>
+#include "gpgme_backend_debug.h"
+
+#include "context.h"
+
+#include <QByteArray>
+#include <QStringList>
+
+#include <gpg-error.h>
+
+#include <assert.h>
+
+QGpgME::QGpgMERefreshKeysJob::QGpgMERefreshKeysJob()
+ : RefreshKeysJob(0),
+ mProcess(0),
+ mError(0)
+{
+
+}
+
+QGpgME::QGpgMERefreshKeysJob::~QGpgMERefreshKeysJob()
+{
+
+}
+
+GpgME::Error QGpgME::QGpgMERefreshKeysJob::start(const QStringList &patterns)
+{
+ assert(mPatternsToDo.empty());
+
+ mPatternsToDo = patterns;
+ if (mPatternsToDo.empty()) {
+ mPatternsToDo.push_back(QStringLiteral(" ")); // empty list means all -> mae
+ }
+ // sure to fail the first
+ // startAProcess() guard clause
+
+ return startAProcess();
+}
+
+#if MAX_CMD_LENGTH < 65 + 128
+#error MAX_CMD_LENGTH is too low
+#endif
+
+GpgME::Error QGpgME::QGpgMERefreshKeysJob::startAProcess()
+{
+ if (mPatternsToDo.empty()) {
+ return GpgME::Error();
+ }
+ // create and start gpgsm process:
+ mProcess = new QProcess(this);
+ mProcess->setObjectName(QStringLiteral("gpgsm -k --with-validation --force-crl-refresh --enable-crl-checks"));
+
+ // FIXME: obbtain the path to gpgsm from gpgme, so we use the same instance.
+ mProcess->setProgram(QStringLiteral("gpgsm"));
+ QStringList arguments;
+ arguments << QStringLiteral("-k")
+ << QStringLiteral("--with-validation")
+ << QStringLiteral("--force-crl-refresh")
+ << QStringLiteral("--enable-crl-checks");
+ unsigned int commandLineLength = MAX_CMD_LENGTH;
+ commandLineLength -=
+ strlen("gpgsm") + 1 + strlen("-k") + 1 +
+ strlen("--with-validation") + 1 + strlen("--force-crl-refresh") + 1 +
+ strlen("--enable-crl-checks") + 1;
+ while (!mPatternsToDo.empty()) {
+ const QByteArray pat = mPatternsToDo.front().toUtf8().trimmed();
+ const unsigned int patLength = pat.length();
+ if (patLength >= commandLineLength) {
+ break;
+ }
+ mPatternsToDo.pop_front();
+ if (pat.isEmpty()) {
+ continue;
+ }
+ arguments << QLatin1String(pat);
+ commandLineLength -= patLength + 1;
+ }
+
+ mProcess->setArguments(arguments);
+
+ connect(mProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
+ SLOT(slotProcessExited(int,QProcess::ExitStatus)));
+ connect(mProcess, SIGNAL(readyReadStandardOutput()),
+ SLOT(slotStdout()));
+ connect(mProcess, &QProcess::readyReadStandardError,
+ this, &QGpgMERefreshKeysJob::slotStderr);
+
+ mProcess->start();
+ if (!mProcess->waitForStarted()) {
+ mError = GpgME::Error::fromCode(GPG_ERR_ENOENT, GPG_ERR_SOURCE_GPGSM); // what else?
+ deleteLater();
+ return mError;
+ } else {
+ return GpgME::Error();
+ }
+}
+
+void QGpgME::QGpgMERefreshKeysJob::slotCancel()
+{
+ if (mProcess) {
+ mProcess->kill();
+ }
+ mProcess = 0;
+ mError = GpgME::Error::fromCode(GPG_ERR_CANCELED, GPG_ERR_SOURCE_GPGSM);
+}
+
+void QGpgME::QGpgMERefreshKeysJob::slotStatus(QProcess *proc, const QString &type, const QStringList &args)
+{
+ if (proc != mProcess) {
+ return;
+ }
+ QStringList::const_iterator it = args.begin();
+ bool ok = false;
+
+ if (type == QLatin1String("ERROR")) {
+
+ if (args.size() < 2) {
+ qCDebug(GPGPME_BACKEND_LOG) << "not recognising ERROR with < 2 args!";
+ return;
+ }
+ const int source = (*++it).toInt(&ok);
+ if (!ok) {
+ qCDebug(GPGPME_BACKEND_LOG) << "expected number for first ERROR arg, got something else";
+ return;
+ }
+ ok = false;
+ const int code = (*++it).toInt(&ok);
+ if (!ok) {
+ qCDebug(GPGPME_BACKEND_LOG) << "expected number for second ERROR arg, got something else";
+ return;
+ }
+ mError = GpgME::Error::fromCode(code, source);
+
+ } else if (type == QLatin1String("PROGRESS")) {
+
+ if (args.size() < 4) {
+ qCDebug(GPGPME_BACKEND_LOG) << "not recognising PROGRESS with < 4 args!";
+ return;
+ }
+ const QString what = *++it;
+ ok = false;
+ (*++it).toInt(&ok);
+ if (!ok) {
+ qCDebug(GPGPME_BACKEND_LOG) << "expected number for \"type\", got something else";
+ return;
+ }
+ ok = false;
+ const int cur = (*++it).toInt(&ok);
+ if (!ok) {
+ qCDebug(GPGPME_BACKEND_LOG) << "expected number for \"cur\", got something else";
+ return;
+ }
+ ok = false;
+ const int total = (*++it).toInt(&ok);
+ if (!ok) {
+ qCDebug(GPGPME_BACKEND_LOG) << "expected number for \"total\", got something else";
+ return;
+ }
+ // TODO port
+ Q_EMIT progress(QString(), cur, total);
+
+ }
+}
+
+void QGpgME::QGpgMERefreshKeysJob::slotStderr()
+{
+ // implement? or not?
+}
+
+void QGpgME::QGpgMERefreshKeysJob::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ if (!mError && !mPatternsToDo.empty()) {
+ if (const GpgME::Error err = startAProcess()) {
+ mError = err;
+ } else {
+ return;
+ }
+ }
+
+ Q_EMIT done();
+ if (!mError &&
+ (exitStatus != QProcess::NormalExit || exitCode != 0)) {
+ mError = GpgME::Error::fromCode(GPG_ERR_GENERAL, GPG_ERR_SOURCE_GPGSM);
+ }
+ Q_EMIT result(mError);
+ deleteLater();
+}
+#include "qgpgmerefreshkeysjob.moc"
diff --git a/lang/qt/src/qgpgmerefreshkeysjob.h b/lang/qt/src/qgpgmerefreshkeysjob.h
new file mode 100644
index 0000000..2a54e38
--- /dev/null
+++ b/lang/qt/src/qgpgmerefreshkeysjob.h
@@ -0,0 +1,79 @@
+/*
+ qgpgmerefreshkeysjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEREFRESHKEYSJOB_H__
+#define __QGPGME_QGPGMEREFRESHKEYSJOB_H__
+
+#include "refreshkeysjob.h"
+#ifdef BUILDING_QGPGME
+# include "context.h"
+#else
+#include "gpgme++/context.h"
+#endif
+
+#include <QStringList>
+#include <QProcess>
+
+namespace QGpgME
+{
+
+class QGpgMERefreshKeysJob : public RefreshKeysJob
+{
+ Q_OBJECT
+public:
+ QGpgMERefreshKeysJob();
+ ~QGpgMERefreshKeysJob();
+
+ /* from RefreshKeysJob */
+ GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ /* from Job */
+ void slotCancel() Q_DECL_OVERRIDE;
+
+ void slotStatus(QProcess *, const QString &, const QStringList &);
+ void slotStderr();
+ void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
+
+private:
+ GpgME::Error startAProcess();
+
+private:
+ QProcess *mProcess;
+ GpgME::Error mError;
+ QStringList mPatternsToDo;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEREFRESHKEYSJOB_H__
diff --git a/lang/qt/src/qgpgmesecretkeyexportjob.cpp b/lang/qt/src/qgpgmesecretkeyexportjob.cpp
new file mode 100644
index 0000000..f4ec698
--- /dev/null
+++ b/lang/qt/src/qgpgmesecretkeyexportjob.cpp
@@ -0,0 +1,142 @@
+/*
+ qgpgmesecretexportjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klar�vdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmesecretkeyexportjob.h"
+
+#include <QDebug>
+#include "gpgme_backend_debug.h"
+
+#include "context.h"
+#include "data.h"
+
+#include <QStringList>
+
+#include <gpg-error.h>
+
+#include <string.h>
+#include <assert.h>
+
+QGpgME::QGpgMESecretKeyExportJob::QGpgMESecretKeyExportJob(bool armour, const QString &charset)
+ : ExportJob(0),
+ mProcess(0),
+ mError(0),
+ mArmour(armour),
+ mCharset(charset)
+{
+
+}
+
+QGpgME::QGpgMESecretKeyExportJob::~QGpgMESecretKeyExportJob()
+{
+
+}
+
+GpgME::Error QGpgME::QGpgMESecretKeyExportJob::start(const QStringList &patterns)
+{
+ assert(mKeyData.isEmpty());
+
+ if (patterns.size() != 1 || patterns.front().isEmpty()) {
+ deleteLater();
+ return mError = GpgME::Error::fromCode(GPG_ERR_INV_VALUE, GPG_ERR_SOURCE_GPGSM);
+ }
+
+ // create and start gpgsm process:
+ mProcess = new QProcess(this);
+ mProcess->setObjectName(QStringLiteral("gpgsm --export-secret-key-p12"));
+
+ // FIXME: obtain the path to gpgsm from gpgme, so we use the same instance.
+ mProcess->setProgram("gpgsm");
+ QStringList arguments;
+ arguments << QStringLiteral("--export-secret-key-p12");
+ if (mArmour) {
+ arguments << QStringLiteral("--armor");
+ }
+ if (!mCharset.isEmpty()) {
+ arguments << QStringLiteral("--p12-charset") << mCharset;
+ }
+ arguments << QLatin1String(patterns.front().toUtf8());
+
+ mProcess->setArguments(arguments);
+ connect(mProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
+ SLOT(slotProcessExited(int,QProcess::ExitStatus)));
+ connect(mProcess, &QProcess::readyReadStandardOutput,
+ this, &QGpgMESecretKeyExportJob::slotStdout);
+ connect(mProcess, &QProcess::readyReadStandardError,
+ this, &QGpgMESecretKeyExportJob::slotStderr);
+
+ mProcess->start();
+ if (!mProcess->waitForStarted()) {
+ mError = GpgME::Error::fromCode(GPG_ERR_ENOENT, GPG_ERR_SOURCE_GPGSM); // what else?
+ deleteLater();
+ return mError;
+ } else {
+ return GpgME::Error();
+ }
+}
+
+void QGpgME::QGpgMESecretKeyExportJob::slotCancel()
+{
+ if (mProcess) {
+ mProcess->kill();
+ }
+ mProcess = 0;
+ mError = GpgME::Error::fromCode(GPG_ERR_CANCELED, GPG_ERR_SOURCE_GPGSM);
+}
+
+void QGpgME::QGpgMESecretKeyExportJob::slotStdout()
+{
+ QString line = QString::fromLocal8Bit(mProcess->readLine());
+ if (!line.isEmpty()) {
+ return;
+ }
+ const unsigned int oldlen = mKeyData.size();
+ mKeyData.resize(oldlen + line.length());
+ memcpy(mKeyData.data() + oldlen, line.toLatin1(), line.length());
+}
+
+void QGpgME::QGpgMESecretKeyExportJob::slotStderr()
+{
+ // implement? or not?
+}
+
+void QGpgME::QGpgMESecretKeyExportJob::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ Q_EMIT done();
+ if (!mError &&
+ (exitStatus != QProcess::NormalExit || exitCode != 0)) {
+ mError = GpgME::Error::fromCode(GPG_ERR_GENERAL, GPG_ERR_SOURCE_GPGSM);
+ }
+ Q_EMIT result(mError, mKeyData);
+ deleteLater();
+}
+#include "qgpgmesecretkeyexportjob.moc"
diff --git a/lang/qt/src/qgpgmesecretkeyexportjob.h b/lang/qt/src/qgpgmesecretkeyexportjob.h
new file mode 100644
index 0000000..ad53f99
--- /dev/null
+++ b/lang/qt/src/qgpgmesecretkeyexportjob.h
@@ -0,0 +1,81 @@
+/*
+ qgpgmesecretkeyexportjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMESECRETKEYEXPORTJOB_H__
+#define __QGPGME_QGPGMESECRETKEYEXPORTJOB_H__
+
+#include "exportjob.h"
+#ifdef BUILDING_QGPGME
+# include "context.h"
+#else
+#include "gpgme++/context.h"
+#endif
+#include <QProcess>
+
+namespace GpgME
+{
+class Data;
+}
+
+namespace QGpgME
+{
+
+class QGpgMESecretKeyExportJob : public ExportJob
+{
+ Q_OBJECT
+public:
+ QGpgMESecretKeyExportJob(bool armour, const QString &charset);
+ ~QGpgMESecretKeyExportJob();
+
+ /* from ExportJob */
+ GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ /* from Job */
+ void slotCancel() Q_DECL_OVERRIDE;
+
+ void slotStdout();
+ void slotStderr();
+ void slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus);
+
+private:
+ QProcess *mProcess;
+ QByteArray mKeyData;
+ GpgME::Error mError;
+ bool mArmour;
+ QString mCharset;
+};
+
+}
+
+#endif // __QGPGME_QGPGMESECRETKEYEXPORTJOB_H__
diff --git a/lang/qt/src/qgpgmesignencryptjob.cpp b/lang/qt/src/qgpgmesignencryptjob.cpp
new file mode 100644
index 0000000..d2e45b1
--- /dev/null
+++ b/lang/qt/src/qgpgmesignencryptjob.cpp
@@ -0,0 +1,171 @@
+/*
+ qgpgmesignencryptjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmesignencryptjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "key.h"
+#include "exception.h"
+
+#include <QBuffer>
+
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMESignEncryptJob::QGpgMESignEncryptJob(Context *context)
+ : mixin_type(context),
+ mOutputIsBase64Encoded(false)
+{
+ lateInitialization();
+}
+
+QGpgMESignEncryptJob::~QGpgMESignEncryptJob() {}
+
+void QGpgMESignEncryptJob::setOutputIsBase64Encoded(bool on)
+{
+ mOutputIsBase64Encoded = on;
+}
+
+static QGpgMESignEncryptJob::result_type sign_encrypt(Context *ctx, QThread *thread, const std::vector<Key> &signers,
+ const std::vector<Key> &recipients, const std::weak_ptr<QIODevice> &plainText_,
+ const std::weak_ptr<QIODevice> &cipherText_, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
+{
+ const std::shared_ptr<QIODevice> &plainText = plainText_.lock();
+ const std::shared_ptr<QIODevice> &cipherText = cipherText_.lock();
+
+ const _detail::ToThreadMover ctMover(cipherText, thread);
+ const _detail::ToThreadMover ptMover(plainText, thread);
+
+ QGpgME::QIODeviceDataProvider in(plainText);
+ const Data indata(&in);
+
+ ctx->clearSigningKeys();
+ Q_FOREACH (const Key &signer, signers)
+ if (!signer.isNull())
+ if (const Error err = ctx->addSigningKey(signer)) {
+ return std::make_tuple(SigningResult(err), EncryptionResult(), QByteArray(), QString(), Error());
+ }
+
+ if (!cipherText) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const std::pair<SigningResult, EncryptionResult> res = ctx->signAndEncrypt(recipients, indata, outdata, eflags);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res.first, res.second, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(cipherText);
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const std::pair<SigningResult, EncryptionResult> res = ctx->signAndEncrypt(recipients, indata, outdata, eflags);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res.first, res.second, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMESignEncryptJob::result_type sign_encrypt_qba(Context *ctx, const std::vector<Key> &signers,
+ const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(plainText);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return sign_encrypt(ctx, 0, signers, recipients, buffer, std::shared_ptr<QIODevice>(), eflags, outputIsBsse64Encoded);
+}
+
+Error QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
+{
+ run(std::bind(&sign_encrypt_qba, std::placeholders::_1, signers, recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, mOutputIsBase64Encoded));
+ return Error();
+}
+
+void QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, const Context::EncryptionFlags eflags)
+{
+ run(std::bind(&sign_encrypt, std::placeholders::_1, std::placeholders::_2, signers, recipients, std::placeholders::_3, std::placeholders::_4, eflags, mOutputIsBase64Encoded), plainText, cipherText);
+}
+
+void QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+{
+ return start(signers, recipients, plainText, cipherText, alwaysTrust ? Context::AlwaysTrust : Context::None);
+}
+
+std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, QByteArray &cipherText)
+{
+ const result_type r = sign_encrypt_qba(context(), signers, recipients, plainText, eflags, mOutputIsBase64Encoded);
+ cipherText = std::get<2>(r);
+ resultHook(r);
+ return mResult;
+}
+
+std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+ return exec(signers, recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, cipherText);
+}
+
+
+#if 0
+
+TODO port?
+void QGpgMESignEncryptJob::showErrorDialog(QWidget *parent, const QString &caption) const
+{
+ if ((mResult.first.error() && !mResult.first.error().isCanceled()) ||
+ (mResult.second.error() && !mResult.second.error().isCanceled())) {
+ MessageBox::error(parent, mResult.first, mResult.second, this, caption);
+ }
+}
+#endif
+
+void QGpgMESignEncryptJob::resultHook(const result_type &tuple)
+{
+ mResult = std::make_pair(std::get<0>(tuple), std::get<1>(tuple));
+}
+#include "qgpgmesignencryptjob.moc"
diff --git a/lang/qt/src/qgpgmesignencryptjob.h b/lang/qt/src/qgpgmesignencryptjob.h
new file mode 100644
index 0000000..e76c245
--- /dev/null
+++ b/lang/qt/src/qgpgmesignencryptjob.h
@@ -0,0 +1,121 @@
+/*
+ qgpgmesignencryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMESIGNENCRYPTJOB_H__
+#define __QGPGME_QGPGMESIGNENCRYPTJOB_H__
+
+#include "signencryptjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "signingresult.h"
+#else
+#include <gpgme++/signingresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "encryptionresult.h"
+#else
+#include <gpgme++/encryptionresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+#include <utility>
+
+namespace QGpgME
+{
+
+class QGpgMESignEncryptJob
+#ifdef Q_MOC_RUN
+ : public SignEncryptJob
+#else
+ : public _detail::ThreadedJobMixin<SignEncryptJob, std::tuple<GpgME::SigningResult, GpgME::EncryptionResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMESignEncryptJob(GpgME::Context *context);
+ ~QGpgMESignEncryptJob();
+
+ /* from SignEncryptJob */
+ GpgME::Error start(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, bool alwaysTrust) Q_DECL_OVERRIDE;
+
+ /* from SignEncryptJob */
+ void start(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText,
+ bool alwaysTrust) Q_DECL_OVERRIDE;
+
+ void start(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText,
+ const GpgME::Context::EncryptionFlags flags) Q_DECL_OVERRIDE;
+
+ std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+ exec(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, bool alwaysTrust,
+ QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+ std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+ exec(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText, const GpgME::Context::EncryptionFlags flags,
+ QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+ /* from SignEncryptJob */
+ void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ bool mOutputIsBase64Encoded;
+ std::pair<GpgME::SigningResult, GpgME::EncryptionResult> mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMESIGNENCRYPTJOB_H__
diff --git a/lang/qt/src/qgpgmesignjob.cpp b/lang/qt/src/qgpgmesignjob.cpp
new file mode 100644
index 0000000..4e2312b
--- /dev/null
+++ b/lang/qt/src/qgpgmesignjob.cpp
@@ -0,0 +1,163 @@
+/*
+ qgpgmesignjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmesignjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "signingresult.h"
+#include "data.h"
+
+#include <QBuffer>
+
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMESignJob::QGpgMESignJob(Context *context)
+ : mixin_type(context),
+ mOutputIsBase64Encoded(false)
+{
+ lateInitialization();
+}
+
+QGpgMESignJob::~QGpgMESignJob() {}
+
+void QGpgMESignJob::setOutputIsBase64Encoded(bool on)
+{
+ mOutputIsBase64Encoded = on;
+}
+
+static QGpgMESignJob::result_type sign(Context *ctx, QThread *thread,
+ const std::vector<Key> &signers,
+ const std::weak_ptr<QIODevice> &plainText_,
+ const std::weak_ptr<QIODevice> &signature_,
+ SignatureMode mode,
+ bool outputIsBsse64Encoded)
+{
+
+ const std::shared_ptr<QIODevice> plainText = plainText_.lock();
+ const std::shared_ptr<QIODevice> signature = signature_.lock();
+
+ const _detail::ToThreadMover ptMover(plainText, thread);
+ const _detail::ToThreadMover sgMover(signature, thread);
+
+ QGpgME::QIODeviceDataProvider in(plainText);
+ const Data indata(&in);
+
+ ctx->clearSigningKeys();
+ Q_FOREACH (const Key &signer, signers)
+ if (!signer.isNull())
+ if (const Error err = ctx->addSigningKey(signer)) {
+ return std::make_tuple(SigningResult(err), QByteArray(), QString(), Error());
+ }
+
+ if (!signature) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const SigningResult res = ctx->sign(indata, outdata, mode);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(signature);
+ Data outdata(&out);
+
+ if (outputIsBsse64Encoded) {
+ outdata.setEncoding(Data::Base64Encoding);
+ }
+
+ const SigningResult res = ctx->sign(indata, outdata, mode);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMESignJob::result_type sign_qba(Context *ctx,
+ const std::vector<Key> &signers,
+ const QByteArray &plainText,
+ SignatureMode mode,
+ bool outputIsBsse64Encoded)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(plainText);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return sign(ctx, 0, signers, buffer, std::shared_ptr<QIODevice>(), mode, outputIsBsse64Encoded);
+}
+
+Error QGpgMESignJob::start(const std::vector<Key> &signers, const QByteArray &plainText, SignatureMode mode)
+{
+ run(std::bind(&sign_qba, std::placeholders::_1, signers, plainText, mode, mOutputIsBase64Encoded));
+ return Error();
+}
+
+void QGpgMESignJob::start(const std::vector<Key> &signers, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &signature, SignatureMode mode)
+{
+ run(std::bind(&sign, std::placeholders::_1, std::placeholders::_2, signers, std::placeholders::_3, std::placeholders::_4, mode, mOutputIsBase64Encoded), plainText, signature);
+}
+
+SigningResult QGpgMESignJob::exec(const std::vector<Key> &signers, const QByteArray &plainText, SignatureMode mode, QByteArray &signature)
+{
+ const result_type r = sign_qba(context(), signers, plainText, mode, mOutputIsBase64Encoded);
+ signature = std::get<1>(r);
+ resultHook(r);
+ return mResult;
+}
+
+void QGpgMESignJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+
+#if 0
+TODO port
+void QGpgMESignJob::showErrorDialog(QWidget *parent, const QString &caption) const
+{
+ if (mResult.error() && !mResult.error().isCanceled()) {
+ MessageBox::error(parent, mResult, this, caption);
+ }
+}
+#endif
+#include "qgpgmesignjob.moc"
diff --git a/lang/qt/src/qgpgmesignjob.h b/lang/qt/src/qgpgmesignjob.h
new file mode 100644
index 0000000..1d4a174
--- /dev/null
+++ b/lang/qt/src/qgpgmesignjob.h
@@ -0,0 +1,101 @@
+/*
+ qgpgmesignjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMESIGNJOB_H__
+#define __QGPGME_QGPGMESIGNJOB_H__
+
+#include "signjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "signingresult.h"
+#else
+#include <gpgme++/signingresult.h>
+#endif
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMESignJob
+#ifdef Q_MOC_RUN
+ : public SignJob
+#else
+ : public _detail::ThreadedJobMixin<SignJob, std::tuple<GpgME::SigningResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMESignJob(GpgME::Context *context);
+ ~QGpgMESignJob();
+
+ /* from SignJob */
+ GpgME::Error start(const std::vector<GpgME::Key> &signers,
+ const QByteArray &plainText,
+ GpgME::SignatureMode mode) Q_DECL_OVERRIDE;
+
+ /* from SignJob */
+ void start(const std::vector<GpgME::Key> &signers,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &signature,
+ GpgME::SignatureMode mode) Q_DECL_OVERRIDE;
+
+ /* from SignJob */
+ GpgME::SigningResult exec(const std::vector<GpgME::Key> &signers,
+ const QByteArray &plainText,
+ GpgME::SignatureMode mode,
+ QByteArray &signature) Q_DECL_OVERRIDE;
+
+ /* from SignJob */
+ void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::SigningResult mResult;
+ bool mOutputIsBase64Encoded;
+};
+
+}
+
+#endif // __QGPGME_QGPGMESIGNJOB_H__
diff --git a/lang/qt/src/qgpgmesignkeyjob.cpp b/lang/qt/src/qgpgmesignkeyjob.cpp
new file mode 100644
index 0000000..e6c1478
--- /dev/null
+++ b/lang/qt/src/qgpgmesignkeyjob.cpp
@@ -0,0 +1,125 @@
+/*
+ qgpgmesignkeyjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmesignkeyjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "data.h"
+#include "gpgsignkeyeditinteractor.h"
+
+#include <cassert>
+#include <memory>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMESignKeyJob::QGpgMESignKeyJob(Context *context)
+ : mixin_type(context),
+ m_userIDsToSign(),
+ m_signingKey(),
+ m_checkLevel(0),
+ m_exportable(false),
+ m_nonRevocable(false),
+ m_started(false)
+{
+ lateInitialization();
+}
+
+QGpgMESignKeyJob::~QGpgMESignKeyJob() {}
+
+static QGpgMESignKeyJob::result_type sign_key(Context *ctx, const Key &key, const std::vector<unsigned int> &uids, unsigned int checkLevel, const Key &signer, unsigned int opts)
+{
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+
+ GpgSignKeyEditInteractor *skei(new GpgSignKeyEditInteractor);
+ skei->setUserIDsToSign(uids);
+ skei->setCheckLevel(checkLevel);
+ skei->setSigningOptions(opts);
+
+ if (!signer.isNull())
+ if (const Error err = ctx->addSigningKey(signer)) {
+ return std::make_tuple(err, QString(), Error());
+ }
+ const Error err = ctx->edit(key, std::unique_ptr<EditInteractor> (skei), data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(err, log, ae);
+}
+
+Error QGpgMESignKeyJob::start(const Key &key)
+{
+ unsigned int opts = 0;
+ if (m_nonRevocable) {
+ opts |= GpgSignKeyEditInteractor::NonRevocable;
+ }
+ if (m_exportable) {
+ opts |= GpgSignKeyEditInteractor::Exportable;
+ }
+ run(std::bind(&sign_key, std::placeholders::_1, key, m_userIDsToSign, m_checkLevel, m_signingKey, opts));
+ m_started = true;
+ return Error();
+}
+
+void QGpgMESignKeyJob::setUserIDsToSign(const std::vector<unsigned int> &idsToSign)
+{
+ assert(!m_started);
+ m_userIDsToSign = idsToSign;
+}
+
+void QGpgMESignKeyJob::setCheckLevel(unsigned int checkLevel)
+{
+ assert(!m_started);
+ m_checkLevel = checkLevel;
+}
+
+void QGpgMESignKeyJob::setExportable(bool exportable)
+{
+ assert(!m_started);
+ m_exportable = exportable;
+}
+
+void QGpgMESignKeyJob::setSigningKey(const Key &key)
+{
+ assert(!m_started);
+ m_signingKey = key;
+}
+
+void QGpgMESignKeyJob::setNonRevocable(bool nonRevocable)
+{
+ assert(!m_started);
+ m_nonRevocable = nonRevocable;
+}
+#include "qgpgmesignkeyjob.moc"
diff --git a/lang/qt/src/qgpgmesignkeyjob.h b/lang/qt/src/qgpgmesignkeyjob.h
new file mode 100644
index 0000000..6cdb7db
--- /dev/null
+++ b/lang/qt/src/qgpgmesignkeyjob.h
@@ -0,0 +1,94 @@
+/*
+ qgpgmesignkeyjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMESIGNKEYJOB_H__
+#define __QGPGME_QGPGMESIGNKEYJOB_H__
+
+#include "signkeyjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "key.h"
+#else
+#include <gpgme++/key.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMESignKeyJob
+#ifdef Q_MOC_RUN
+ : public SignKeyJob
+#else
+ : public _detail::ThreadedJobMixin<SignKeyJob>
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMESignKeyJob(GpgME::Context *context);
+ ~QGpgMESignKeyJob();
+
+ /* from SignKeyJob */
+ GpgME::Error start(const GpgME::Key &key) Q_DECL_OVERRIDE;
+
+ /* from SignKeyJob */
+ void setUserIDsToSign(const std::vector<unsigned int> &idsToSign) Q_DECL_OVERRIDE;
+
+ /* from SignKeyJob */
+ void setCheckLevel(unsigned int checkLevel) Q_DECL_OVERRIDE;
+
+ /* from SignKeyJob */
+ void setExportable(bool exportable) Q_DECL_OVERRIDE;
+
+ /* from SignKeyJob */
+ void setSigningKey(const GpgME::Key &key) Q_DECL_OVERRIDE;
+
+ /* from SignKeyJob */
+ void setNonRevocable(bool nonRevocable) Q_DECL_OVERRIDE;
+
+private:
+ std::vector<unsigned int> m_userIDsToSign;
+ GpgME::Key m_signingKey;
+ unsigned int m_checkLevel;
+ bool m_exportable;
+ bool m_nonRevocable;
+ bool m_started;
+};
+}
+
+#endif // __QGPGME_QGPGMESIGNKEYJOB_H__
diff --git a/lang/qt/src/qgpgmetofupolicyjob.cpp b/lang/qt/src/qgpgmetofupolicyjob.cpp
new file mode 100644
index 0000000..a24c946
--- /dev/null
+++ b/lang/qt/src/qgpgmetofupolicyjob.cpp
@@ -0,0 +1,65 @@
+/* qgpgmetofupolicyjob.cpp
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmetofupolicyjob.h"
+
+#include "context.h"
+#include "key.h"
+#include "tofuinfo.h"
+
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMETofuPolicyJob::QGpgMETofuPolicyJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMETofuPolicyJob::~QGpgMETofuPolicyJob() {}
+
+static QGpgMETofuPolicyJob::result_type policy_worker(Context *ctx, const Key &key, TofuInfo::Policy policy)
+{
+ return std::make_tuple (ctx->setTofuPolicy(key, policy),
+ QString(), Error());
+}
+
+void QGpgMETofuPolicyJob::start(const Key &key, TofuInfo::Policy policy)
+{
+ run(std::bind(&policy_worker, std::placeholders::_1, key, policy));
+}
+
+Error QGpgMETofuPolicyJob::exec(const Key &key, TofuInfo::Policy policy)
+{
+ return std::get<0>(policy_worker(context(), key, policy));
+}
+
+#include "qgpgmetofupolicyjob.moc"
diff --git a/lang/qt/src/qgpgmetofupolicyjob.h b/lang/qt/src/qgpgmetofupolicyjob.h
new file mode 100644
index 0000000..e7272e7
--- /dev/null
+++ b/lang/qt/src/qgpgmetofupolicyjob.h
@@ -0,0 +1,65 @@
+/* qgpgmetofupolicyjob.h
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef QGPGME_QGPGMETOFUPOLICYJOB_H
+#define QGPGME_QGPGMETOFUPOLICYJOB_H
+
+#include "tofupolicyjob.h"
+
+#include "threadedjobmixin.h"
+namespace GpgME
+{
+ class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+class QGpgMETofuPolicyJob
+#ifdef Q_MOC_RUN
+ : public TofuPolicyJob
+#else
+ : public _detail::ThreadedJobMixin<TofuPolicyJob, std::tuple<GpgME::Error, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMETofuPolicyJob(GpgME::Context *context);
+ ~QGpgMETofuPolicyJob();
+
+ void start(const GpgME::Key &key, GpgME::TofuInfo::Policy policy) Q_DECL_OVERRIDE;
+ GpgME::Error exec(const GpgME::Key &key, GpgME::TofuInfo::Policy policy) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif
diff --git a/lang/qt/src/qgpgmeverifydetachedjob.cpp b/lang/qt/src/qgpgmeverifydetachedjob.cpp
new file mode 100644
index 0000000..8efef05
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifydetachedjob.cpp
@@ -0,0 +1,118 @@
+/*
+ qgpgmeverifydetachedjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeverifydetachedjob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "verificationresult.h"
+#include "data.h"
+
+#include <cassert>
+
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEVerifyDetachedJob::QGpgMEVerifyDetachedJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEVerifyDetachedJob::~QGpgMEVerifyDetachedJob() {}
+
+static QGpgMEVerifyDetachedJob::result_type verify_detached(Context *ctx, QThread *thread, const std::weak_ptr<QIODevice> &signature_, const std::weak_ptr<QIODevice> &signedData_)
+{
+ const std::shared_ptr<QIODevice> signature = signature_.lock();
+ const std::shared_ptr<QIODevice> signedData = signedData_.lock();
+
+ const _detail::ToThreadMover sgMover(signature, thread);
+ const _detail::ToThreadMover sdMover(signedData, thread);
+
+ QGpgME::QIODeviceDataProvider sigDP(signature);
+ Data sig(&sigDP);
+
+ QGpgME::QIODeviceDataProvider dataDP(signedData);
+ Data data(&dataDP);
+
+ const VerificationResult res = ctx->verifyDetachedSignature(sig, data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+
+ return std::make_tuple(res, log, ae);
+}
+
+static QGpgMEVerifyDetachedJob::result_type verify_detached_qba(Context *ctx, const QByteArray &signature, const QByteArray &signedData)
+{
+ QGpgME::QByteArrayDataProvider sigDP(signature);
+ Data sig(&sigDP);
+
+ QGpgME::QByteArrayDataProvider dataDP(signedData);
+ Data data(&dataDP);
+
+ const VerificationResult res = ctx->verifyDetachedSignature(sig, data);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+
+ return std::make_tuple(res, log, ae);
+
+}
+
+Error QGpgMEVerifyDetachedJob::start(const QByteArray &signature, const QByteArray &signedData)
+{
+ run(std::bind(&verify_detached_qba, std::placeholders::_1, signature, signedData));
+ return Error();
+}
+
+void QGpgMEVerifyDetachedJob::start(const std::shared_ptr<QIODevice> &signature, const std::shared_ptr<QIODevice> &signedData)
+{
+ run(std::bind(&verify_detached, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), signature, signedData);
+}
+
+GpgME::VerificationResult QGpgME::QGpgMEVerifyDetachedJob::exec(const QByteArray &signature,
+ const QByteArray &signedData)
+{
+ const result_type r = verify_detached_qba(context(), signature, signedData);
+ resultHook(r);
+ return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgME::QGpgMEVerifyDetachedJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+#include "qgpgmeverifydetachedjob.moc"
diff --git a/lang/qt/src/qgpgmeverifydetachedjob.h b/lang/qt/src/qgpgmeverifydetachedjob.h
new file mode 100644
index 0000000..051caf0
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifydetachedjob.h
@@ -0,0 +1,85 @@
+/*
+ qgpgmeverifydetachedjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEVERIFYDETACHEDJOB_H__
+#define __QGPGME_QGPGMEVERIFYDETACHEDJOB_H__
+
+#include "verifydetachedjob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "verificationresult.h"
+#else
+#include <gpgme++/verificationresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEVerifyDetachedJob
+#ifdef Q_MOC_RUN
+ : public VerifyDetachedJob
+#else
+ : public _detail::ThreadedJobMixin<VerifyDetachedJob, std::tuple<GpgME::VerificationResult, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEVerifyDetachedJob(GpgME::Context *context);
+ ~QGpgMEVerifyDetachedJob();
+
+ /* from VerifyDetachedJob */
+ GpgME::Error start(const QByteArray &signature, const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+ /* from VerifyDetachedJob */
+ void start(const std::shared_ptr<QIODevice> &signature, const std::shared_ptr<QIODevice> &signedData) Q_DECL_OVERRIDE;
+
+ /* from VerifyDetachedJob */
+ GpgME::VerificationResult exec(const QByteArray &signature,
+ const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::VerificationResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEVERIFYDETACHEDJOB_H__
diff --git a/lang/qt/src/qgpgmeverifyopaquejob.cpp b/lang/qt/src/qgpgmeverifyopaquejob.cpp
new file mode 100644
index 0000000..b513f82
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifyopaquejob.cpp
@@ -0,0 +1,125 @@
+/*
+ qgpgmeverifyopaquejob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmeverifyopaquejob.h"
+
+#include "dataprovider.h"
+
+#include "context.h"
+#include "verificationresult.h"
+#include "data.h"
+
+#include <QBuffer>
+
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEVerifyOpaqueJob::QGpgMEVerifyOpaqueJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEVerifyOpaqueJob::~QGpgMEVerifyOpaqueJob() {}
+
+static QGpgMEVerifyOpaqueJob::result_type verify_opaque(Context *ctx, QThread *thread, const std::weak_ptr<QIODevice> &signedData_, const std::weak_ptr<QIODevice> &plainText_)
+{
+
+ const std::shared_ptr<QIODevice> plainText = plainText_.lock();
+ const std::shared_ptr<QIODevice> signedData = signedData_.lock();
+
+ const _detail::ToThreadMover ptMover(plainText, thread);
+ const _detail::ToThreadMover sdMover(signedData, thread);
+
+ QGpgME::QIODeviceDataProvider in(signedData);
+ const Data indata(&in);
+
+ if (!plainText) {
+ QGpgME::QByteArrayDataProvider out;
+ Data outdata(&out);
+
+ const VerificationResult res = ctx->verifyOpaqueSignature(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, out.data(), log, ae);
+ } else {
+ QGpgME::QIODeviceDataProvider out(plainText);
+ Data outdata(&out);
+
+ const VerificationResult res = ctx->verifyOpaqueSignature(indata, outdata);
+ Error ae;
+ const QString log = _detail::audit_log_as_html(ctx, ae);
+ return std::make_tuple(res, QByteArray(), log, ae);
+ }
+
+}
+
+static QGpgMEVerifyOpaqueJob::result_type verify_opaque_qba(Context *ctx, const QByteArray &signedData)
+{
+ const std::shared_ptr<QBuffer> buffer(new QBuffer);
+ buffer->setData(signedData);
+ if (!buffer->open(QIODevice::ReadOnly)) {
+ assert(!"This should never happen: QBuffer::open() failed");
+ }
+ return verify_opaque(ctx, 0, buffer, std::shared_ptr<QIODevice>());
+}
+
+Error QGpgMEVerifyOpaqueJob::start(const QByteArray &signedData)
+{
+ run(std::bind(&verify_opaque_qba, std::placeholders::_1, signedData));
+ return Error();
+}
+
+void QGpgMEVerifyOpaqueJob::start(const std::shared_ptr<QIODevice> &signedData, const std::shared_ptr<QIODevice> &plainText)
+{
+ run(std::bind(&verify_opaque, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), signedData, plainText);
+}
+
+GpgME::VerificationResult QGpgME::QGpgMEVerifyOpaqueJob::exec(const QByteArray &signedData, QByteArray &plainText)
+{
+ const result_type r = verify_opaque_qba(context(), signedData);
+ plainText = std::get<1>(r);
+ resultHook(r);
+ return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgME::QGpgMEVerifyOpaqueJob::resultHook(const result_type &tuple)
+{
+ mResult = std::get<0>(tuple);
+}
+#include "qgpgmeverifyopaquejob.moc"
diff --git a/lang/qt/src/qgpgmeverifyopaquejob.h b/lang/qt/src/qgpgmeverifyopaquejob.h
new file mode 100644
index 0000000..87c94a3
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifyopaquejob.h
@@ -0,0 +1,84 @@
+/*
+ qgpgmeverifyopaquejob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_QGPGMEVERIFYOPAQUEJOB_H__
+#define __QGPGME_QGPGMEVERIFYOPAQUEJOB_H__
+
+#include "verifyopaquejob.h"
+
+#include "threadedjobmixin.h"
+
+#ifdef BUILDING_QGPGME
+# include "verificationresult.h"
+#else
+#include <gpgme++/verificationresult.h>
+#endif
+
+namespace QGpgME
+{
+
+class QGpgMEVerifyOpaqueJob
+#ifdef Q_MOC_RUN
+ : public VerifyOpaqueJob
+#else
+ : public _detail::ThreadedJobMixin<VerifyOpaqueJob, std::tuple<GpgME::VerificationResult, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEVerifyOpaqueJob(GpgME::Context *context);
+ ~QGpgMEVerifyOpaqueJob();
+
+ /* from VerifyOpaqueJob */
+ GpgME::Error start(const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+ /* from VerifyOpaqueJob */
+ void start(const std::shared_ptr<QIODevice> &signedData, const std::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+ /* form VerifyOpaqueJob */
+ GpgME::VerificationResult exec(const QByteArray &signedData, QByteArray &plainData) Q_DECL_OVERRIDE;
+
+ /* from ThreadedJobMixin */
+ void resultHook(const result_type &r) Q_DECL_OVERRIDE;
+
+private:
+ GpgME::VerificationResult mResult;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEVERIFYOPAQUEJOB_H__
diff --git a/lang/qt/src/qgpgmewkspublishjob.cpp b/lang/qt/src/qgpgmewkspublishjob.cpp
new file mode 100644
index 0000000..8f97cb5
--- /dev/null
+++ b/lang/qt/src/qgpgmewkspublishjob.cpp
@@ -0,0 +1,189 @@
+/* wkspublishjob.cpp
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "qgpgmewkspublishjob.h"
+
+#include "context.h"
+#include "key.h"
+#include "util.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <QProcess>
+
+/* Timeout for the WKS Processes will be 5 Minutes as
+ * they can involve pinentry questions. */
+#define TIMEOUT_VALUE (5*60*1000)
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEWKSPublishJob::QGpgMEWKSPublishJob(Context *context)
+ : mixin_type(context)
+{
+ lateInitialization();
+}
+
+QGpgMEWKSPublishJob::~QGpgMEWKSPublishJob() {}
+
+static QString getWKSClient()
+{
+ auto libexecdir = QString::fromLocal8Bit(dirInfo("libexecdir"));
+ if (libexecdir.isEmpty()) {
+ return QString();
+ }
+
+ const QFileInfo fi(QDir(libexecdir).absoluteFilePath(QStringLiteral("gpg-wks-client")));
+ if (fi.exists() && fi.isExecutable()) {
+ return fi.absoluteFilePath();
+ }
+ return QString();
+}
+
+static QGpgMEWKSPublishJob::result_type check_worker(const QString &mail)
+{
+ if (mail.isEmpty()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ const auto wksPath = getWKSClient();
+ if (wksPath.isEmpty()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ /* QProcess instead of engine_spawn because engine_spawn does not communicate
+ * the return value of the process and we are in qt anyway. */
+ QProcess proc;
+ proc.setProgram(wksPath);
+ proc.setArguments(QStringList() << QStringLiteral("--supported") << mail);
+ proc.start();
+ if (!proc.waitForStarted()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+ if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+ return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+ if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+ return std::make_tuple (Error(), QByteArray(), QByteArray(), QString(), Error());
+ }
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_ENABLED)),
+ QByteArray(), QByteArray(), QString(), Error());
+}
+
+static QGpgMEWKSPublishJob::result_type create_worker(const char *fpr, const QString &mail)
+{
+ if (mail.isEmpty() || !fpr) {
+ return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ const auto wksPath = getWKSClient();
+ if (wksPath.isEmpty()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ QProcess proc;
+ proc.setProgram(wksPath);
+ proc.setArguments(QStringList() << QStringLiteral("--create")
+ << QLatin1String(fpr)
+ << mail);
+ proc.start();
+ if (!proc.waitForStarted()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+ return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+ if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+ return std::make_tuple (Error(), proc.readAllStandardOutput(),
+ proc.readAllStandardError(), QString(), Error());
+ }
+ return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
+ proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
+}
+
+static QGpgMEWKSPublishJob::result_type recieve_worker(const QByteArray &response)
+{
+ if (response.isEmpty()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ const auto wksPath = getWKSClient();
+ if (wksPath.isEmpty()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+
+ QProcess proc;
+ proc.setProgram(wksPath);
+ proc.setArguments(QStringList() << QStringLiteral("--receive"));
+ proc.start();
+ if (!proc.waitForStarted()) {
+ return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+ proc.write(response);
+ proc.closeWriteChannel();
+ if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+ return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+ QByteArray(), QByteArray(), QString(), Error());
+ }
+ if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+ return std::make_tuple (Error(), proc.readAllStandardOutput(),
+ proc.readAllStandardError(), QString(), Error());
+ }
+ return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
+ proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
+}
+
+void QGpgMEWKSPublishJob::startCheck(const QString &mailbox)
+{
+ run(std::bind(&check_worker, mailbox));
+}
+
+void QGpgMEWKSPublishJob::startCreate(const char *fpr, const QString &mailbox) {
+ run(std::bind(&create_worker, fpr, mailbox));
+}
+
+void QGpgMEWKSPublishJob::startRecieve(const QByteArray &response)
+{
+ run(std::bind(&recieve_worker, response));
+}
+
+#include "qgpgmewkspublishjob.moc"
diff --git a/lang/qt/src/qgpgmewkspublishjob.h b/lang/qt/src/qgpgmewkspublishjob.h
new file mode 100644
index 0000000..1a31149
--- /dev/null
+++ b/lang/qt/src/qgpgmewkspublishjob.h
@@ -0,0 +1,70 @@
+/* qgpgmewkspublishjob.h
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef QGPGME_QGPGMEWKSPUBLISHJOB_H
+#define QGPGME_QGPGMEWKSPUBLISHJOB_H
+
+#include "wkspublishjob.h"
+
+#include "threadedjobmixin.h"
+namespace GpgME
+{
+ class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+/**
+ * Handles Web Key Service Publishing. Needs WKS tools installed and
+ * server support.
+ */
+class QGpgMEWKSPublishJob
+#ifdef Q_MOC_RUN
+ : public WKSPublishJob
+#else
+ : public _detail::ThreadedJobMixin<WKSPublishJob, std::tuple<GpgME::Error, QByteArray, QByteArray, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEWKSPublishJob(GpgME::Context *context);
+ ~QGpgMEWKSPublishJob();
+
+ void startCheck(const QString &mailbox) Q_DECL_OVERRIDE;
+ void startCreate(const char *fpr, const QString &mailbox) Q_DECL_OVERRIDE;
+ void startRecieve(const QByteArray &response) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif
diff --git a/lang/qt/src/refreshkeysjob.h b/lang/qt/src/refreshkeysjob.h
new file mode 100644
index 0000000..a97de80
--- /dev/null
+++ b/lang/qt/src/refreshkeysjob.h
@@ -0,0 +1,94 @@
+/*
+ refreshkeysjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_REFRESHKEYSJOB_H__
+#define __KLEO_REFRESHKEYSJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#include <vector>
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+class QStringList;
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous key refreshers.
+
+ To use a RefreshKeysJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the key refresh with a
+ call to start(). This call might fail, in which case the
+ RefreshKeysJob instance will have scheduled its own destruction
+ with a call to QObject::deleteLater().
+
+ After result() is emitted, the KeyListJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT RefreshKeysJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit RefreshKeysJob(QObject *parent);
+public:
+ ~RefreshKeysJob();
+
+ /**
+ Starts the keylist operation. \a pattern is a list of patterns
+ used to restrict the list of keys returned. Empty patterns are
+ ignored. If \a pattern is empty or contains only empty strings,
+ all keys are returned (however, the backend is free to truncate
+ the result and should do so; when this happens, it will be
+ reported by the reult object).
+
+ If \a secretOnly is true, only keys for which the secret key is
+ also available are returned. Use this if you need to select a
+ key for signing.
+ */
+ virtual GpgME::Error start(const QStringList &patterns) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &error);
+};
+
+}
+
+#endif // __KLEO_REFRESHKEYSJOB_H__
diff --git a/lang/qt/src/signencryptjob.h b/lang/qt/src/signencryptjob.h
new file mode 100644
index 0000000..4e07744
--- /dev/null
+++ b/lang/qt/src/signencryptjob.h
@@ -0,0 +1,153 @@
+/*
+ signencryptjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_SIGNENCRYPTJOB_H__
+#define __KLEO_SIGNENCRYPTJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#ifdef BUILDING_QGPGME
+# include "global.h"
+# include "context.h"
+#else
+# include <gpgme++/global.h>
+# include <gpgme++/context.h>
+#endif
+
+#include <memory>
+#include <vector>
+#include <utility>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class Key;
+class SigningResult;
+class EncryptionResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous combined signing and encrypting
+
+ To use a SignEncryptJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the operation with a
+ call to start(). This call might fail, in which case the
+ SignEncryptJob instance will have scheduled it's own destruction
+ with a call to QObject::deleteLater().
+
+ After result() is emitted, the SignEncryptJob will schedule it's
+ own destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT SignEncryptJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit SignEncryptJob(QObject *parent);
+public:
+ ~SignEncryptJob();
+
+ /**
+ Starts the combined signing and encrypting operation. \a signers
+ is the list of keys to sign \a plainText with. \a recipients is
+ a list of keys to encrypt the signed \a plainText to. In both
+ lists, empty (null) keys are ignored.
+
+ If \a alwaysTrust is true, validity checking for the
+ \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,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText,
+ bool alwaysTrust = false) = 0;
+
+ /*!
+ \overload
+
+ If \a cipherText is non-null, the ciphertext is written
+ there. Otherwise, it will be delivered in the third argument of
+ result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+ bool alwaysTrust = false) = 0;
+
+ virtual std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+ exec(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText,
+ bool alwaysTrust, QByteArray &cipherText) = 0;
+
+ /*!
+ This is a hack to request BASE64 output (instead of whatever
+ comes out normally).
+ */
+ virtual void setOutputIsBase64Encoded(bool) = 0;
+
+ /** Like start but with an additional argument for EncryptionFlags for
+ * more flexibility. */
+ virtual void start(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+ const GpgME::Context::EncryptionFlags flags = GpgME::Context::None) = 0;
+
+ /** Like exec but with an additional argument for EncryptionFlags for
+ * more flexibility. */
+ virtual std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+ exec(const std::vector<GpgME::Key> &signers,
+ const std::vector<GpgME::Key> &recipients,
+ const QByteArray &plainText,
+ const GpgME::Context::EncryptionFlags flags, QByteArray &cipherText) = 0;
+Q_SIGNALS:
+ void result(const GpgME::SigningResult &signingresult,
+ const GpgME::EncryptionResult &encryptionresult,
+ const QByteArray &cipherText, const QString &auditLogAsHtml = QString(),
+ const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_SIGNENCRYPTJOB_H__
diff --git a/lang/qt/src/signjob.h b/lang/qt/src/signjob.h
new file mode 100644
index 0000000..cf5c628
--- /dev/null
+++ b/lang/qt/src/signjob.h
@@ -0,0 +1,122 @@
+/*
+ signjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_SIGNJOB_H__
+#define __KLEO_SIGNJOB_H__
+
+#include "job.h"
+
+#ifdef BUILDING_QGPGME
+# include "global.h"
+#else
+# include <gpgme++/global.h>
+#endif
+
+
+#include <vector>
+#include <memory>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class Key;
+class SigningResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous signing
+
+ To use a SignJob, first obtain an instance from the CryptoBackend
+ implementation, connect the progress() and result() signals to
+ suitable slots and then start the signing with a call to
+ start(). This call might fail, in which case the SignJob instance
+ will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the SignJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT SignJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit SignJob(QObject *parent);
+public:
+ ~SignJob();
+
+ /**
+ Starts the signing operation. \a signers is the list of keys to
+ sign \a plainText with. Empty (null) keys are ignored.
+ */
+ virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const std::vector<GpgME::Key> &signers,
+ const QByteArray &plainText,
+ GpgME::SignatureMode mode) = 0;
+
+ /*!
+ \overload
+
+ If \a signature is non-null the signature is written
+ there. Otherwise, it will be delivered in the second argument of
+ result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::vector<GpgME::Key> &signers,
+ const std::shared_ptr<QIODevice> &plainText,
+ const std::shared_ptr<QIODevice> &signature,
+ GpgME::SignatureMode mode) = 0;
+
+ virtual GpgME::SigningResult exec(const std::vector<GpgME::Key> &signers,
+ const QByteArray &plainText,
+ GpgME::SignatureMode mode,
+ QByteArray &signature) = 0;
+
+ /*!
+ This is a hack to request BASE64 output (instead of whatever
+ comes out normally).
+ */
+ virtual void setOutputIsBase64Encoded(bool) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::SigningResult &result, const QByteArray &signature, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_SIGNJOB_H__
diff --git a/lang/qt/src/signkeyjob.h b/lang/qt/src/signkeyjob.h
new file mode 100644
index 0000000..b5efc01
--- /dev/null
+++ b/lang/qt/src/signkeyjob.h
@@ -0,0 +1,117 @@
+/*
+ signkeyjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_SIGNKEYJOB_H__
+#define __KLEO_SIGNKEYJOB_H__
+
+#include "job.h"
+
+#include <vector>
+
+namespace GpgME
+{
+class Error;
+class Key;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class to sign keys asynchronously
+
+ To use a SignKeyJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the job with a call
+ to start(). This call might fail, in which case the ChangeExpiryJob
+ instance will have scheduled it's own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the SignKeyJob will schedule it's own
+ destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT SignKeyJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit SignKeyJob(QObject *parent);
+public:
+ ~SignKeyJob();
+
+ /**
+ Starts the key signing operation. \a key is the key to sign.
+ @param keyToSign the key to be signed
+ @param idsToSign the user IDs to sign
+ @param signingKey the secret key to use for signing
+ @param option the signing mode, either local or exportable
+ */
+ virtual GpgME::Error start(const GpgME::Key &keyToSign) = 0;
+
+ /**
+ * If explicitly specified, only the listed user IDs will be signed. Otherwise all user IDs
+ * are signed.
+ * @param list of user ID indexes (of the key to be signed).
+ */
+ virtual void setUserIDsToSign(const std::vector<unsigned int> &idsToSign) = 0;
+
+ /**
+ * sets the check level
+ * @param the check level, ranges from 0 (no claim) and 3 (extensively checked),
+ * default is 0
+ */
+ virtual void setCheckLevel(unsigned int checkLevel) = 0;
+
+ /**
+ * sets whether the signature should be exportable, or local only.
+ * default is local.
+ */
+ virtual void setExportable(bool exportable) = 0;
+
+ /**
+ * sets an alternate signing key
+ */
+ virtual void setSigningKey(const GpgME::Key &key) = 0;
+
+ /**
+ * if set, the created signature won't be revocable. By default signatures
+ * can be revoked.
+ */
+ virtual void setNonRevocable(bool nonRevocable) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_SIGNKEYJOB_H__
diff --git a/lang/qt/src/specialjob.h b/lang/qt/src/specialjob.h
new file mode 100644
index 0000000..2c80f20
--- /dev/null
+++ b/lang/qt/src/specialjob.h
@@ -0,0 +1,91 @@
+/*
+ specialjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_SPECIALJOB_H__
+#define __KLEO_SPECIALJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+namespace GpgME
+{
+class Error;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for protocol-specific jobs
+
+ To use a SpecialJob, first obtain an instance from the
+ CryptoBackend implementation, connect progress() and result()
+ signals to suitable slots and then start the job with a call to
+ start(). This call might fail, in which case the SpecialJob
+ instance will have schedules its own destruction with a call to
+ QObject::deleteLater().
+
+ After result() is emitted, the SpecialJob will schedule its own
+ destruction by calling QObject::deleteLater().
+
+ Parameters are set using the Qt property system. More general, or
+ constructor parameters are given in the call to
+ QGpgME::Protocol::specialJob().
+
+ The result is made available through the result signal, and
+ through the read-only result property, the latter of which needs
+ to be defined in each SpecialJob subclass.
+*/
+class QGPGME_EXPORT SpecialJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit SpecialJob(QObject *parent);
+
+public:
+ ~SpecialJob();
+
+ /**
+ Starts the special operation.
+ */
+ virtual GpgME::Error start() = 0;
+
+ virtual GpgME::Error exec() = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::Error &result, const QVariant &data);
+};
+
+}
+
+#endif // __KLEO_SPECIALJOB_H__
diff --git a/lang/qt/src/threadedjobmixin.cpp b/lang/qt/src/threadedjobmixin.cpp
new file mode 100644
index 0000000..cd6ab5f
--- /dev/null
+++ b/lang/qt/src/threadedjobmixin.cpp
@@ -0,0 +1,110 @@
+/*
+ threadedjobmixin.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "threadedjobmixin.h"
+
+#include "dataprovider.h"
+
+#include "data.h"
+
+#include <QString>
+#include <QStringList>
+#include <QByteArray>
+
+
+#include <algorithm>
+#include <iterator>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+static const unsigned int GetAuditLogFlags = Context::AuditLogWithHelp | Context::HtmlAuditLog;
+
+QString _detail::audit_log_as_html(Context *ctx, GpgME::Error &err)
+{
+ assert(ctx);
+ QGpgME::QByteArrayDataProvider dp;
+ Data data(&dp);
+ assert(!data.isNull());
+ if ((err = ctx->lastError()) || (err = ctx->getAuditLog(data, GetAuditLogFlags))) {
+ return QString::fromLocal8Bit(err.asString());
+ }
+ const QByteArray ba = dp.data();
+ return QString::fromUtf8(ba.data(), ba.size());
+}
+
+static QList<QByteArray> from_sl(const QStringList &sl)
+{
+ QList<QByteArray> result;
+ Q_FOREACH (const QString &str, sl) {
+ result.append(str.toUtf8());
+ }
+
+#if 0
+ std::transform(sl.begin(), sl.end(), std::back_inserter(result),
+ mem_fn(static_cast<QByteArray()const>(&QString::toUtf8)));
+#endif
+ return result;
+}
+
+static QList<QByteArray> single(const QByteArray &ba)
+{
+ QList<QByteArray> result;
+ result.push_back(ba);
+ return result;
+}
+
+_detail::PatternConverter::PatternConverter(const QByteArray &ba)
+ : m_list(single(ba)), m_patterns(0) {}
+_detail::PatternConverter::PatternConverter(const QString &s)
+ : m_list(single(s.toUtf8())), m_patterns(0) {}
+_detail::PatternConverter::PatternConverter(const QList<QByteArray> &lba)
+ : m_list(lba), m_patterns(0) {}
+_detail::PatternConverter::PatternConverter(const QStringList &sl)
+ : m_list(from_sl(sl)), m_patterns(0) {}
+
+const char **_detail::PatternConverter::patterns() const
+{
+ if (!m_patterns) {
+ m_patterns = new const char *[ m_list.size() + 1 ];
+ const char **end = std::transform(m_list.begin(), m_list.end(), m_patterns,
+ std::mem_fn(&QByteArray::constData));
+ *end = 0;
+ }
+ return m_patterns;
+}
+
+_detail::PatternConverter::~PatternConverter()
+{
+ delete [] m_patterns;
+}
diff --git a/lang/qt/src/threadedjobmixin.h b/lang/qt/src/threadedjobmixin.h
new file mode 100644
index 0000000..62d7f1c
--- /dev/null
+++ b/lang/qt/src/threadedjobmixin.h
@@ -0,0 +1,272 @@
+/*
+ threadedjobmixin.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2008 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __QGPGME_THREADEDJOBMIXING_H__
+#define __QGPGME_THREADEDJOBMIXING_H__
+
+#include <QMutex>
+#include <QMutexLocker>
+#include <QThread>
+#include <QString>
+#include <QIODevice>
+
+#ifdef BUILDING_QGPGME
+# include "context.h"
+# include "interfaces/progressprovider.h"
+#else
+# include <gpgme++/context.h>
+# include <gpgme++/interfaces/progressprovider.h>
+#endif
+
+
+#include <cassert>
+
+namespace QGpgME
+{
+namespace _detail
+{
+
+QString audit_log_as_html(GpgME::Context *ctx, GpgME::Error &err);
+
+class PatternConverter
+{
+ const QList<QByteArray> m_list;
+ mutable const char **m_patterns;
+public:
+ explicit PatternConverter(const QByteArray &ba);
+ explicit PatternConverter(const QString &s);
+ explicit PatternConverter(const QList<QByteArray> &lba);
+ explicit PatternConverter(const QStringList &sl);
+ ~PatternConverter();
+
+ const char **patterns() const;
+};
+
+class ToThreadMover
+{
+ QObject *const m_object;
+ QThread *const m_thread;
+public:
+ ToThreadMover(QObject *o, QThread *t) : m_object(o), m_thread(t) {}
+ ToThreadMover(QObject &o, QThread *t) : m_object(&o), m_thread(t) {}
+ ToThreadMover(const std::shared_ptr<QObject> &o, QThread *t) : m_object(o.get()), m_thread(t) {}
+ ~ToThreadMover()
+ {
+ if (m_object && m_thread) {
+ m_object->moveToThread(m_thread);
+ }
+ }
+};
+
+template <typename T_result>
+class Thread : public QThread
+{
+public:
+ explicit Thread(QObject *parent = Q_NULLPTR) : QThread(parent) {}
+
+ void setFunction(const std::function<T_result()> &function)
+ {
+ const QMutexLocker locker(&m_mutex);
+ m_function = function;
+ }
+
+ T_result result() const
+ {
+ const QMutexLocker locker(&m_mutex);
+ return m_result;
+ }
+
+private:
+ void run() Q_DECL_OVERRIDE {
+ const QMutexLocker locker(&m_mutex);
+ m_result = m_function();
+ }
+private:
+ mutable QMutex m_mutex;
+ std::function<T_result()> m_function;
+ T_result m_result;
+};
+
+template <typename T_base, typename T_result = std::tuple<GpgME::Error, QString, GpgME::Error> >
+class ThreadedJobMixin : public T_base, public GpgME::ProgressProvider
+{
+public:
+ typedef ThreadedJobMixin<T_base, T_result> mixin_type;
+ typedef T_result result_type;
+
+protected:
+ static_assert(std::tuple_size<T_result>::value > 2,
+ "Result tuple too small");
+ static_assert(std::is_same <
+ typename std::tuple_element <
+ std::tuple_size<T_result>::value - 2,
+ T_result
+ >::type,
+ QString
+ >::value,
+ "Second to last result type not a QString");
+ static_assert(std::is_same <
+ typename std::tuple_element <
+ std::tuple_size<T_result>::value - 1,
+ T_result
+ >::type,
+ GpgME::Error
+ >::value,
+ "Last result type not a GpgME::Error");
+
+ explicit ThreadedJobMixin(GpgME::Context *ctx)
+ : T_base(0), m_ctx(ctx), m_thread(), m_auditLog(), m_auditLogError()
+ {
+
+ }
+
+ void lateInitialization()
+ {
+ assert(m_ctx);
+ QObject::connect(&m_thread, SIGNAL(finished()), this, SLOT(slotFinished()));
+ m_ctx->setProgressProvider(this);
+ }
+
+ template <typename T_binder>
+ void run(const T_binder &func)
+ {
+ m_thread.setFunction(std::bind(func, this->context()));
+ m_thread.start();
+ }
+ template <typename T_binder>
+ void run(const T_binder &func, const std::shared_ptr<QIODevice> &io)
+ {
+ if (io) {
+ io->moveToThread(&m_thread);
+ }
+ // the arguments passed here to the functor are stored in a QThread, and are not
+ // necessarily destroyed (living outside the UI thread) at the time the result signal
+ // is emitted and the signal receiver wants to clean up IO devices.
+ // To avoid such races, we pass std::weak_ptr's to the functor.
+ m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io)));
+ m_thread.start();
+ }
+ template <typename T_binder>
+ void run(const T_binder &func, const std::shared_ptr<QIODevice> &io1, const std::shared_ptr<QIODevice> &io2)
+ {
+ if (io1) {
+ io1->moveToThread(&m_thread);
+ }
+ if (io2) {
+ io2->moveToThread(&m_thread);
+ }
+ // the arguments passed here to the functor are stored in a QThread, and are not
+ // necessarily destroyed (living outside the UI thread) at the time the result signal
+ // is emitted and the signal receiver wants to clean up IO devices.
+ // To avoid such races, we pass std::weak_ptr's to the functor.
+ m_thread.setFunction(std::bind(func, this->context(), this->thread(), std::weak_ptr<QIODevice>(io1), std::weak_ptr<QIODevice>(io2)));
+ m_thread.start();
+ }
+ GpgME::Context *context() const
+ {
+ return m_ctx.get();
+ }
+
+ virtual void resultHook(const result_type &) {}
+
+ void slotFinished()
+ {
+ const T_result r = m_thread.result();
+ m_auditLog = std::get < std::tuple_size<T_result>::value - 2 > (r);
+ m_auditLogError = std::get < std::tuple_size<T_result>::value - 1 > (r);
+ resultHook(r);
+ Q_EMIT this->done();
+ doEmitResult(r);
+ this->deleteLater();
+ }
+ void slotCancel() Q_DECL_OVERRIDE {
+ if (m_ctx)
+ {
+ m_ctx->cancelPendingOperation();
+ }
+ }
+ QString auditLogAsHtml() const Q_DECL_OVERRIDE
+ {
+ return m_auditLog;
+ }
+ GpgME::Error auditLogError() const Q_DECL_OVERRIDE
+ {
+ return m_auditLogError;
+ }
+ void showProgress(const char *what, int type, int current, int total) Q_DECL_OVERRIDE {
+ // will be called from the thread exec'ing the operation, so
+ // just bounce everything to the owning thread:
+ // ### hope this is thread-safe (meta obj is const, and
+ // ### portEvent is thread-safe, so should be ok)
+ QMetaObject::invokeMethod(this, "progress", Qt::QueuedConnection,
+ // TODO port
+ Q_ARG(QString, QString()),
+ Q_ARG(int, current),
+ Q_ARG(int, total));
+ }
+private:
+ template <typename T1, typename T2>
+ void doEmitResult(const std::tuple<T1, T2> &tuple)
+ {
+ Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple));
+ }
+
+ template <typename T1, typename T2, typename T3>
+ void doEmitResult(const std::tuple<T1, T2, T3> &tuple)
+ {
+ Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple));
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ void doEmitResult(const std::tuple<T1, T2, T3, T4> &tuple)
+ {
+ Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple));
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ void doEmitResult(const std::tuple<T1, T2, T3, T4, T5> &tuple)
+ {
+ Q_EMIT this->result(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple), std::get<3>(tuple), std::get<4>(tuple));
+ }
+
+private:
+ std::shared_ptr<GpgME::Context> m_ctx;
+ Thread<T_result> m_thread;
+ QString m_auditLog;
+ GpgME::Error m_auditLogError;
+};
+
+}
+}
+
+#endif /* __QGPGME_THREADEDJOBMIXING_H__ */
diff --git a/lang/qt/src/tofupolicyjob.h b/lang/qt/src/tofupolicyjob.h
new file mode 100644
index 0000000..3079f91
--- /dev/null
+++ b/lang/qt/src/tofupolicyjob.h
@@ -0,0 +1,80 @@
+/* tofupolicyjob.h
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef QGPGME_TOFUPOLICYJOB_H
+#define QGPGME_TOFUPOLICYJOB_H
+
+#include "job.h"
+
+#include "qgpgme_export.h"
+
+#ifdef BUILDING_QGPGME
+# include "tofuinfo.h"
+#else
+# include <gpgme++/tofuinfo.h>
+#endif
+
+namespace GpgME
+{
+ class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+/**
+ * Set the TOFU Policy for a key
+ */
+class QGPGME_EXPORT TofuPolicyJob: public Job
+{
+ Q_OBJECT
+protected:
+ explicit TofuPolicyJob(QObject *parent);
+public:
+ ~TofuPolicyJob();
+
+
+ /* Set the policy to \a policy see the gpgme manual for
+ * policy explanations. */
+ virtual void start(const GpgME::Key &key, GpgME::TofuInfo::Policy policy) = 0;
+
+ virtual GpgME::Error exec(const GpgME::Key &key, GpgME::TofuInfo::Policy policy) = 0;
+
+Q_SIGNALS:
+ /* Result of the operation
+ *
+ * As usual auditLogAsHtml and auditLogError can be ignored.
+ **/
+ void result(const GpgME::Error &error,
+ const QString &auditLogAsHtml = QString(),
+ const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif
diff --git a/lang/qt/src/verifydetachedjob.h b/lang/qt/src/verifydetachedjob.h
new file mode 100644
index 0000000..b339a8c
--- /dev/null
+++ b/lang/qt/src/verifydetachedjob.h
@@ -0,0 +1,99 @@
+/*
+ verifydetachedjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_VERIFYDETACHEDJOB_H__
+#define __KLEO_VERIFYDETACHEDJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+#include <memory>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class VerificationResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous verification of detached signatures
+
+ To use a VerifyDetachedJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the verification with a
+ call to start(). This call might fail, in which case the
+ VerifyDetachedJob instance will have scheduled it's own
+ destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the VerifyDetachedJob will schedule
+ it's own destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT VerifyDetachedJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit VerifyDetachedJob(QObject *parent);
+public:
+ ~VerifyDetachedJob();
+
+ /**
+ Starts the verification operation. \a signature contains the
+ signature data, while \a signedData contains the data over
+ which the signature was made.
+ */
+ virtual QGPGME_DEPRECATED_EXPORT GpgME::Error start(const QByteArray &signature,
+ const QByteArray &signedData) = 0;
+
+ /*!
+ \overload
+
+ \throws GpgME::Exception if starting fails.
+ */
+ virtual void start(const std::shared_ptr<QIODevice> &signature, const std::shared_ptr<QIODevice> &signedData) = 0;
+
+ virtual GpgME::VerificationResult exec(const QByteArray &signature,
+ const QByteArray &signedData) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::VerificationResult &result, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_VERIFYDETACHEDJOB_H__
diff --git a/lang/qt/src/verifyopaquejob.h b/lang/qt/src/verifyopaquejob.h
new file mode 100644
index 0000000..f064049
--- /dev/null
+++ b/lang/qt/src/verifyopaquejob.h
@@ -0,0 +1,101 @@
+/*
+ verifyopaquejob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2004, 2007 Klarälvdalens Datakonsult AB
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef __KLEO_VERIFYOPAQUEJOB_H__
+#define __KLEO_VERIFYOPAQUEJOB_H__
+
+#include "job.h"
+
+#include <memory>
+
+class QByteArray;
+class QIODevice;
+
+namespace GpgME
+{
+class Error;
+class VerificationResult;
+}
+
+namespace QGpgME
+{
+
+/**
+ @short An abstract base class for asynchronous verification of opaque signatures
+
+ To use a VerifyOpaqueJob, first obtain an instance from the
+ CryptoBackend implementation, connect the progress() and result()
+ signals to suitable slots and then start the verification with a
+ call to start(). This call might fail, in which case the
+ VerifyOpaqueJob instance will have scheduled it's own
+ destruction with a call to QObject::deleteLater().
+
+ After result() is emitted, the VerifyOpaqueJob will schedule
+ it's own destruction by calling QObject::deleteLater().
+*/
+class QGPGME_EXPORT VerifyOpaqueJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit VerifyOpaqueJob(QObject *parent);
+public:
+ ~VerifyOpaqueJob();
+
+ /**
+ Starts the verification operation. \a signature contains the
+ 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;
+
+ /*!
+ \overload
+
+ If \a plainText is non-null, the plaintext is written
+ there. Otherwise, it will be delivered in the second argument
+ of result().
+
+ \throws GpgME::Exception if starting fails
+ */
+ virtual void start(const std::shared_ptr<QIODevice> &signedData, const std::shared_ptr<QIODevice> &plainText = std::shared_ptr<QIODevice>()) = 0;
+
+ /** Synchronous version of @ref start */
+ virtual GpgME::VerificationResult exec(const QByteArray &signedData, QByteArray &plainText) = 0;
+
+Q_SIGNALS:
+ void result(const GpgME::VerificationResult &result, const QByteArray &plainText, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif // __KLEO_VERIFYOPAQUEJOB_H__
diff --git a/lang/qt/src/wkspublishjob.h b/lang/qt/src/wkspublishjob.h
new file mode 100644
index 0000000..782112f
--- /dev/null
+++ b/lang/qt/src/wkspublishjob.h
@@ -0,0 +1,101 @@
+/* wkspublishjob.h
+
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef QGPGME_WKSPUBLISHJOB_H
+#define QGPGME_WKSPUBLISHJOB_H
+
+#include "job.h"
+
+#include "qgpgme_export.h"
+
+namespace GpgME
+{
+ class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+/**
+ * Handles Web Key Service Publishing. Needs WKS tools installed and
+ * server support.
+ *
+ * Remember that after a result is emited the job is auto deleted
+ * so you can only use it for a single action.
+ */
+class QGPGME_EXPORT WKSPublishJob: public Job
+{
+ Q_OBJECT
+protected:
+ explicit WKSPublishJob(QObject *parent);
+public:
+ ~WKSPublishJob();
+
+
+ /** Start a check if WKS Publishing is supported. As this involves
+ * an HTTP Query it might take a while. Returns GPG_ERR_NOT_SUPPORED
+ * result if GnuPG is too old or the required tools are not installed.
+ *
+ * The error GPG_ERR_NOT_ENABLED indicates that wks-tools failed to
+ * detect a working wks service for this.
+ *
+ * @param the mailbox to check for.
+ **/
+ virtual void startCheck(const QString &mailbox) = 0;
+
+ /** Create a publish request.
+ * The returned Data from the result will contain
+ * the full Mail as returned by gpg-wks-client --create
+ *
+ * @param fpr the fingerprint of the key to create the request for.
+ * @param mailbox A simple mail address without a Name.
+ */
+ virtual void startCreate(const char *fpr, const QString &mailbox) = 0;
+
+ /** Handle a submisson response. The returned Data will contain
+ * the full Mail as returned by gpg-wks-client --create
+ *
+ * @param response The response of the server.
+ **/
+ virtual void startRecieve(const QByteArray &response) = 0;
+
+Q_SIGNALS:
+ /* Result of the operation returned Data and returned Error are
+ * the results from gpg-wks-client's stdout or stderr respectively.
+ *
+ * As usual auditLogAsHtml and auditLogError can be ignored.
+ **/
+ void result(const GpgME::Error &error, const QByteArray &returnedData,
+ const QByteArray &returnedError,
+ const QString &auditLogAsHtml = QString(),
+ const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif
diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
new file mode 100644
index 0000000..f243a55
--- /dev/null
+++ b/lang/qt/tests/Makefile.am
@@ -0,0 +1,95 @@
+# Makefile.am - Makefile for GPGME Qt tests.
+# Copyright (C) 2016 Intevation 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/>.
+
+## Process this file with automake to produce Makefile.in
+
+GPG = gpg
+
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir)
+
+EXTRA_DIST = initial.test
+
+TESTS = initial.test t-keylist t-keylocate t-ownertrust t-tofuinfo \
+ t-encrypt t-wkspublish
+
+moc_files = t-keylist.moc t-keylocate.moc t-ownertrust.moc t-tofuinfo.moc \
+ t-encrypt.moc t-support.hmoc t-wkspublish.moc
+
+AM_LDFLAGS = -no-install
+
+LDADD = ../../cpp/src/libgpgmepp.la ../src/libqgpgme.la \
+ ../../../src/libgpgme.la @GPGME_QT_LIBS@ @GPG_ERROR_LIBS@ \
+ @GPGME_QTTEST_LIBS@ -lstdc++
+
+AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
+ @GPG_ERROR_CFLAGS@ @GPGME_QT_CFLAGS@ @GPG_ERROR_CFLAGS@ \
+ @LIBASSUAN_CFLAGS@ @GPGME_QTTEST_CFLAGS@ -DBUILDING_QGPGME \
+ -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)
+t_keylocate_SOURCES = t-keylocate.cpp $(support_src)
+t_ownertrust_SOURCES = t-ownertrust.cpp $(support_src)
+t_tofuinfo_SOURCES = t-tofuinfo.cpp $(support_src)
+t_encrypt_SOURCES = t-encrypt.cpp $(support_src)
+t_wkspublish_SOURCES = t-wkspublish.cpp $(support_src)
+run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp
+
+nodist_t_keylist_SOURCES = $(moc_files)
+
+BUILT_SOURCES = $(moc_files)
+
+noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt \
+ run-keyformailboxjob t-wkspublish
+
+CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
+ gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
+ random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp $(moc_files) \
+ gpg.conf
+
+clean-local:
+ -rm -fR private-keys-v1.d crls.d
+
+export GNUPGHOME := $(abs_builddir)
+
+./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
+ echo "ignore-invalid-option pinentry-mode" > gpg.conf
+ echo "pinentry-mode loopback" >> gpg.conf
+ $(GPG) --no-permission-warning \
+ --import $(top_srcdir)/tests/gpg/pubdemo.asc
+ $(GPG) --no-permission-warning \
+ --passphrase "abc" \
+ --import $(top_srcdir)/tests/gpg/secdemo.asc
+ touch ./pubring-stamp
+
+.cpp.moc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+.h.hmoc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
diff --git a/lang/qt/tests/Makefile.in b/lang/qt/tests/Makefile.in
new file mode 100644
index 0000000..45d4c76
--- /dev/null
+++ b/lang/qt/tests/Makefile.in
@@ -0,0 +1,951 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am - Makefile for GPGME Qt tests.
+# Copyright (C) 2016 Intevation 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/>.
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+TESTS = initial.test t-keylist$(EXEEXT) t-keylocate$(EXEEXT) \
+ t-ownertrust$(EXEEXT) t-tofuinfo$(EXEEXT) t-encrypt$(EXEEXT) \
+ t-wkspublish$(EXEEXT)
+noinst_PROGRAMS = t-keylist$(EXEEXT) t-keylocate$(EXEEXT) \
+ t-ownertrust$(EXEEXT) t-tofuinfo$(EXEEXT) t-encrypt$(EXEEXT) \
+ run-keyformailboxjob$(EXEEXT) t-wkspublish$(EXEEXT)
+subdir = lang/qt/tests
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/mkinstalldirs \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_pkg_swig.m4 \
+ $(top_srcdir)/m4/ax_python_devel.m4 \
+ $(top_srcdir)/m4/glib-2.0.m4 $(top_srcdir)/m4/glibc21.m4 \
+ $(top_srcdir)/m4/gnupg-ttyname.m4 \
+ $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libassuan.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/qt.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/build-aux/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_run_keyformailboxjob_OBJECTS = run-keyformailboxjob.$(OBJEXT)
+run_keyformailboxjob_OBJECTS = $(am_run_keyformailboxjob_OBJECTS)
+run_keyformailboxjob_LDADD = $(LDADD)
+run_keyformailboxjob_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am__objects_1 = t-support.$(OBJEXT)
+am_t_encrypt_OBJECTS = t-encrypt.$(OBJEXT) $(am__objects_1)
+t_encrypt_OBJECTS = $(am_t_encrypt_OBJECTS)
+t_encrypt_LDADD = $(LDADD)
+t_encrypt_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+am_t_keylist_OBJECTS = t-keylist.$(OBJEXT) $(am__objects_1)
+am__objects_2 =
+nodist_t_keylist_OBJECTS = $(am__objects_2)
+t_keylist_OBJECTS = $(am_t_keylist_OBJECTS) \
+ $(nodist_t_keylist_OBJECTS)
+t_keylist_LDADD = $(LDADD)
+t_keylist_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+am_t_keylocate_OBJECTS = t-keylocate.$(OBJEXT) $(am__objects_1)
+t_keylocate_OBJECTS = $(am_t_keylocate_OBJECTS)
+t_keylocate_LDADD = $(LDADD)
+t_keylocate_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+am_t_ownertrust_OBJECTS = t-ownertrust.$(OBJEXT) $(am__objects_1)
+t_ownertrust_OBJECTS = $(am_t_ownertrust_OBJECTS)
+t_ownertrust_LDADD = $(LDADD)
+t_ownertrust_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+am_t_tofuinfo_OBJECTS = t-tofuinfo.$(OBJEXT) $(am__objects_1)
+t_tofuinfo_OBJECTS = $(am_t_tofuinfo_OBJECTS)
+t_tofuinfo_LDADD = $(LDADD)
+t_tofuinfo_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+am_t_wkspublish_OBJECTS = t-wkspublish.$(OBJEXT) $(am__objects_1)
+t_wkspublish_OBJECTS = $(am_t_wkspublish_OBJECTS)
+t_wkspublish_LDADD = $(LDADD)
+t_wkspublish_DEPENDENCIES = ../../cpp/src/libgpgmepp.la \
+ ../src/libqgpgme.la ../../../src/libgpgme.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(run_keyformailboxjob_SOURCES) $(t_encrypt_SOURCES) \
+ $(t_keylist_SOURCES) $(nodist_t_keylist_SOURCES) \
+ $(t_keylocate_SOURCES) $(t_ownertrust_SOURCES) \
+ $(t_tofuinfo_SOURCES) $(t_wkspublish_SOURCES)
+DIST_SOURCES = $(run_keyformailboxjob_SOURCES) $(t_encrypt_SOURCES) \
+ $(t_keylist_SOURCES) $(t_keylocate_SOURCES) \
+ $(t_ownertrust_SOURCES) $(t_tofuinfo_SOURCES) \
+ $(t_wkspublish_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_FILEVERSION = @BUILD_FILEVERSION@
+BUILD_REVISION = @BUILD_REVISION@
+BUILD_TIMESTAMP = @BUILD_TIMESTAMP@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLED_LANGUAGES = @ENABLED_LANGUAGES@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GITLOG_TO_CHANGELOG = @GITLOG_TO_CHANGELOG@
+GLIBC21 = @GLIBC21@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GPGME_CONFIG_API_VERSION = @GPGME_CONFIG_API_VERSION@
+GPGME_CONFIG_AVAIL_LANG = @GPGME_CONFIG_AVAIL_LANG@
+GPGME_CONFIG_CFLAGS = @GPGME_CONFIG_CFLAGS@
+GPGME_CONFIG_HOST = @GPGME_CONFIG_HOST@
+GPGME_CONFIG_LIBS = @GPGME_CONFIG_LIBS@
+GPGME_QTTEST_CFLAGS = @GPGME_QTTEST_CFLAGS@
+GPGME_QTTEST_LIBS = @GPGME_QTTEST_LIBS@
+GPGME_QT_CFLAGS = @GPGME_QT_CFLAGS@
+GPGME_QT_LIBS = @GPGME_QT_LIBS@
+GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@
+GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@
+GPG_ERROR_LIBS = @GPG_ERROR_LIBS@
+GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@
+GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@
+GRAPHVIZ = @GRAPHVIZ@
+GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
+HAVE_DOT = @HAVE_DOT@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBASSUAN_CFLAGS = @LIBASSUAN_CFLAGS@
+LIBASSUAN_CONFIG = @LIBASSUAN_CONFIG@
+LIBASSUAN_LIBS = @LIBASSUAN_LIBS@
+LIBGPGMEPP_LT_AGE = @LIBGPGMEPP_LT_AGE@
+LIBGPGMEPP_LT_CURRENT = @LIBGPGMEPP_LT_CURRENT@
+LIBGPGMEPP_LT_REVISION = @LIBGPGMEPP_LT_REVISION@
+LIBGPGME_LT_AGE = @LIBGPGME_LT_AGE@
+LIBGPGME_LT_CURRENT = @LIBGPGME_LT_CURRENT@
+LIBGPGME_LT_REVISION = @LIBGPGME_LT_REVISION@
+LIBOBJS = @LIBOBJS@
+LIBQGPGME_LT_AGE = @LIBQGPGME_LT_AGE@
+LIBQGPGME_LT_CURRENT = @LIBQGPGME_LT_CURRENT@
+LIBQGPGME_LT_REVISION = @LIBQGPGME_LT_REVISION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MOC = @MOC@
+MOC2 = @MOC2@
+NEED__FILE_OFFSET_BITS = @NEED__FILE_OFFSET_BITS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+PYTHONS = @PYTHONS@
+PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
+PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
+PYTHON_LDFLAGS = @PYTHON_LDFLAGS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
+PYTHON_VERSION = @PYTHON_VERSION@
+PYTHON_VERSIONS = @PYTHON_VERSIONS@
+QTCHOOSER = @QTCHOOSER@
+RANLIB = @RANLIB@
+RC = @RC@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SWIG = @SWIG@
+SWIG_LIB = @SWIG_LIB@
+SYSROOT = @SYSROOT@
+VERSION = @VERSION@
+VERSION_NUMBER = @VERSION_NUMBER@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+emacs_local_vars_begin = @emacs_local_vars_begin@
+emacs_local_vars_end = @emacs_local_vars_end@
+emacs_local_vars_read_only = @emacs_local_vars_read_only@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+GPG = gpg
+TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir)
+EXTRA_DIST = initial.test
+moc_files = t-keylist.moc t-keylocate.moc t-ownertrust.moc t-tofuinfo.moc \
+ t-encrypt.moc t-support.hmoc t-wkspublish.moc
+
+AM_LDFLAGS = -no-install
+LDADD = ../../cpp/src/libgpgmepp.la ../src/libqgpgme.la \
+ ../../../src/libgpgme.la @GPGME_QT_LIBS@ @GPG_ERROR_LIBS@ \
+ @GPGME_QTTEST_LIBS@ -lstdc++
+
+AM_CPPFLAGS = -I$(top_srcdir)/lang/cpp/src -I$(top_builddir)/src \
+ @GPG_ERROR_CFLAGS@ @GPGME_QT_CFLAGS@ @GPG_ERROR_CFLAGS@ \
+ @LIBASSUAN_CFLAGS@ @GPGME_QTTEST_CFLAGS@ -DBUILDING_QGPGME \
+ -I$(top_srcdir)/lang/qt/src \
+ -DTOP_SRCDIR="$(top_srcdir)"
+
+support_src = t-support.h t-support.cpp
+t_keylist_SOURCES = t-keylist.cpp $(support_src)
+t_keylocate_SOURCES = t-keylocate.cpp $(support_src)
+t_ownertrust_SOURCES = t-ownertrust.cpp $(support_src)
+t_tofuinfo_SOURCES = t-tofuinfo.cpp $(support_src)
+t_encrypt_SOURCES = t-encrypt.cpp $(support_src)
+t_wkspublish_SOURCES = t-wkspublish.cpp $(support_src)
+run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp
+nodist_t_keylist_SOURCES = $(moc_files)
+BUILT_SOURCES = $(moc_files)
+CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
+ gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
+ random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp $(moc_files) \
+ gpg.conf
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .h .hmoc .lo .moc .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lang/qt/tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lang/qt/tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+run-keyformailboxjob$(EXEEXT): $(run_keyformailboxjob_OBJECTS) $(run_keyformailboxjob_DEPENDENCIES) $(EXTRA_run_keyformailboxjob_DEPENDENCIES)
+ @rm -f run-keyformailboxjob$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(run_keyformailboxjob_OBJECTS) $(run_keyformailboxjob_LDADD) $(LIBS)
+
+t-encrypt$(EXEEXT): $(t_encrypt_OBJECTS) $(t_encrypt_DEPENDENCIES) $(EXTRA_t_encrypt_DEPENDENCIES)
+ @rm -f t-encrypt$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_encrypt_OBJECTS) $(t_encrypt_LDADD) $(LIBS)
+
+t-keylist$(EXEEXT): $(t_keylist_OBJECTS) $(t_keylist_DEPENDENCIES) $(EXTRA_t_keylist_DEPENDENCIES)
+ @rm -f t-keylist$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_keylist_OBJECTS) $(t_keylist_LDADD) $(LIBS)
+
+t-keylocate$(EXEEXT): $(t_keylocate_OBJECTS) $(t_keylocate_DEPENDENCIES) $(EXTRA_t_keylocate_DEPENDENCIES)
+ @rm -f t-keylocate$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_keylocate_OBJECTS) $(t_keylocate_LDADD) $(LIBS)
+
+t-ownertrust$(EXEEXT): $(t_ownertrust_OBJECTS) $(t_ownertrust_DEPENDENCIES) $(EXTRA_t_ownertrust_DEPENDENCIES)
+ @rm -f t-ownertrust$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_ownertrust_OBJECTS) $(t_ownertrust_LDADD) $(LIBS)
+
+t-tofuinfo$(EXEEXT): $(t_tofuinfo_OBJECTS) $(t_tofuinfo_DEPENDENCIES) $(EXTRA_t_tofuinfo_DEPENDENCIES)
+ @rm -f t-tofuinfo$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_tofuinfo_OBJECTS) $(t_tofuinfo_LDADD) $(LIBS)
+
+t-wkspublish$(EXEEXT): $(t_wkspublish_OBJECTS) $(t_wkspublish_DEPENDENCIES) $(EXTRA_t_wkspublish_DEPENDENCIES)
+ @rm -f t-wkspublish$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(t_wkspublish_OBJECTS) $(t_wkspublish_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run-keyformailboxjob.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-encrypt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-keylist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-keylocate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-ownertrust.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-support.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-tofuinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/t-wkspublish.Po@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst $(AM_TESTS_FD_REDIRECT); then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ fi; \
+ echo "$${col}$$dashes$${std}"; \
+ echo "$${col}$$banner$${std}"; \
+ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \
+ test -z "$$report" || echo "$${col}$$report$${std}"; \
+ echo "$${col}$$dashes$${std}"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am \
+ check-local clean clean-generic clean-libtool clean-local \
+ clean-noinstPROGRAMS cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+
+check-local: ./pubring-stamp
+
+# To guarantee that check-local is run before any tests we
+# add this dependency:
+initial.test : check-local
+
+clean-local:
+ -rm -fR private-keys-v1.d crls.d
+
+export GNUPGHOME := $(abs_builddir)
+
+./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
+ echo "ignore-invalid-option pinentry-mode" > gpg.conf
+ echo "pinentry-mode loopback" >> gpg.conf
+ $(GPG) --no-permission-warning \
+ --import $(top_srcdir)/tests/gpg/pubdemo.asc
+ $(GPG) --no-permission-warning \
+ --passphrase "abc" \
+ --import $(top_srcdir)/tests/gpg/secdemo.asc
+ touch ./pubring-stamp
+
+.cpp.moc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+.h.hmoc:
+ $(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lang/qt/tests/initial.test b/lang/qt/tests/initial.test
new file mode 100755
index 0000000..039e4d0
--- /dev/null
+++ b/lang/qt/tests/initial.test
@@ -0,0 +1,2 @@
+#!/bin/sh
+exit 0
diff --git a/lang/qt/tests/run-keyformailboxjob.cpp b/lang/qt/tests/run-keyformailboxjob.cpp
new file mode 100644
index 0000000..9ac7668
--- /dev/null
+++ b/lang/qt/tests/run-keyformailboxjob.cpp
@@ -0,0 +1,56 @@
+/*
+ run-keyformailbox.cpp
+
+ This file is part of QGpgME's test suite.
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "keyformailboxjob.h"
+#include "keylistjob.h"
+#include "protocol.h"
+
+#include "key.h"
+#include "keylistresult.h"
+
+#include <QDebug>
+
+
+int main(int argc, char **argv)
+{
+ QString mailbox;
+ if (argc == 2) {
+ mailbox = QString::fromLocal8Bit(argv[1]);
+ }
+
+ auto job = QGpgME::openpgp()->keyForMailboxJob();
+ GpgME::Key k;
+ GpgME::UserID uid;
+ job->exec(mailbox, true, k, uid);
+ qDebug() << "UID Name: " << uid.name() << " Mail: " << uid.email() << " id: " << uid.id();
+ qDebug() << "Key fpr: " << k.primaryFingerprint();
+ return 0;
+}
diff --git a/lang/qt/tests/t-encrypt.cpp b/lang/qt/tests/t-encrypt.cpp
new file mode 100644
index 0000000..3d4cfa9
--- /dev/null
+++ b/lang/qt/tests/t-encrypt.cpp
@@ -0,0 +1,254 @@
+/* t-encrypt.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include <QDebug>
+#include <QTest>
+#include <QTemporaryDir>
+#include <QSignalSpy>
+#include <QBuffer>
+#include "keylistjob.h"
+#include "encryptjob.h"
+#include "qgpgmeencryptjob.h"
+#include "encryptionresult.h"
+#include "decryptionresult.h"
+#include "qgpgmedecryptjob.h"
+#include "qgpgmebackend.h"
+#include "keylistresult.h"
+#include "engineinfo.h"
+#include "t-support.h"
+
+#define PROGRESS_TEST_SIZE 1 * 1024 * 1024
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class EncryptionTest : public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+
+ void testSimpleEncryptDecrypt()
+ {
+ auto listjob = openpgp()->keyListJob(false, false, false);
+ std::vector<Key> keys;
+ auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ Q_ASSERT(!keylistresult.error());
+ Q_ASSERT(keys.size() == 1);
+ delete listjob;
+
+ auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
+ Q_ASSERT(job);
+ QByteArray cipherText;
+ auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
+ delete job;
+ Q_ASSERT(!result.error());
+ const auto cipherString = QString::fromUtf8(cipherText);
+ Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+ /* Now decrypt */
+ auto ctx = Context::createForProtocol(OpenPGP);
+ TestPassphraseProvider provider;
+ ctx->setPassphraseProvider(&provider);
+ ctx->setPinentryMode(Context::PinentryLoopback);
+ auto decJob = new QGpgMEDecryptJob(ctx);
+ QByteArray plainText;
+ auto decResult = decJob->exec(cipherText, plainText);
+ Q_ASSERT(!result.error());
+ Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
+ delete decJob;
+ }
+
+ void testProgress()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
+ // We can only test the progress with 2.1.15 as this started to
+ // have total progress for memory callbacks
+ return;
+ }
+ auto listjob = openpgp()->keyListJob(false, false, false);
+ std::vector<Key> keys;
+ auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ Q_ASSERT(!keylistresult.error());
+ Q_ASSERT(keys.size() == 1);
+ delete listjob;
+
+ auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
+ Q_ASSERT(job);
+ QByteArray plainBa;
+ plainBa.fill('X', PROGRESS_TEST_SIZE);
+ QByteArray cipherText;
+
+ bool initSeen = false;
+ bool finishSeen = false;
+ connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString& what, int current, int total) {
+ // We only check for progress 0 and max progress as the other progress
+ // lines depend on the system speed and are as such unreliable to test.
+ Q_ASSERT(total == PROGRESS_TEST_SIZE);
+ if (current == 0) {
+ initSeen = true;
+ }
+ if (current == total) {
+ finishSeen = true;
+ }
+ Q_ASSERT(current >= 0 && current <= total);
+ });
+ connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &result,
+ const QByteArray &cipherText,
+ const QString,
+ const GpgME::Error) {
+ Q_ASSERT(initSeen);
+ Q_ASSERT(finishSeen);
+ Q_EMIT asyncDone();
+ });
+
+ auto inptr = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
+ inptr->open(QIODevice::ReadOnly);
+ auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
+ outptr->open(QIODevice::WriteOnly);
+
+ job->start(keys, inptr, outptr, Context::AlwaysTrust);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+
+ void testSymmetricEncryptDecrypt()
+ {
+ auto ctx = Context::createForProtocol(OpenPGP);
+ 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;
+ Q_ASSERT(!result.error());
+ const auto cipherString = QString::fromUtf8(cipherText);
+ Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+ killAgent(mDir.path());
+
+ auto ctx2 = Context::createForProtocol(OpenPGP);
+ ctx2->setPassphraseProvider(&provider);
+ ctx2->setPinentryMode(Context::PinentryLoopback);
+ auto decJob = new QGpgMEDecryptJob(ctx2);
+ QByteArray plainText;
+ auto decResult = decJob->exec(cipherText, plainText);
+ Q_ASSERT(!result.error());
+ Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
+ delete decJob;
+ }
+
+private:
+ /* Loopback and passphrase provider don't work for mixed encryption.
+ * So this test is disabled until gnupg(?) is fixed for this. */
+ void testMixedEncryptDecrypt()
+ {
+ auto listjob = openpgp()->keyListJob(false, false, false);
+ std::vector<Key> keys;
+ auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ Q_ASSERT(!keylistresult.error());
+ Q_ASSERT(keys.size() == 1);
+ delete listjob;
+
+ auto ctx = Context::createForProtocol(OpenPGP);
+ 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(),
+ static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
+ cipherText);
+ printf("After exec\n");
+ delete job;
+ Q_ASSERT(!result.error());
+ printf("Cipher:\n%s\n", cipherText.constData());
+ const auto cipherString = QString::fromUtf8(cipherText);
+ Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+ killAgent(mDir.path());
+
+ /* Now create a new homedir which with we test symetric decrypt. */
+ QTemporaryDir tmp;
+ qputenv("GNUPGHOME", tmp.path().toUtf8());
+ QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
+ Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+ agentConf.write("allow-loopback-pinentry");
+ agentConf.close();
+
+ auto ctx2 = Context::createForProtocol(OpenPGP);
+ ctx2->setPassphraseProvider(new TestPassphraseProvider);
+ ctx2->setPinentryMode(Context::PinentryLoopback);
+ ctx2->setTextMode(true);
+ auto decJob = new QGpgMEDecryptJob(ctx2);
+ QByteArray plainText;
+ auto decResult = decJob->exec(cipherText, plainText);
+ Q_ASSERT(!decResult.error());
+ qDebug() << "Plain: " << plainText;
+ Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
+ delete decJob;
+
+ killAgent(tmp.path());
+ qputenv("GNUPGHOME", mDir.path().toUtf8());
+ }
+
+public Q_SLOT:
+
+ void initTestCase()
+ {
+ QGpgMETest::initTestCase();
+ const QString gpgHome = qgetenv("GNUPGHOME");
+ qputenv("GNUPGHOME", mDir.path().toUtf8());
+ Q_ASSERT(mDir.isValid());
+ QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
+ Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+ agentConf.write("allow-loopback-pinentry");
+ agentConf.close();
+ Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
+ }
+
+private:
+ QTemporaryDir mDir;
+};
+
+QTEST_MAIN(EncryptionTest)
+
+#include "t-encrypt.moc"
diff --git a/lang/qt/tests/t-keylist.cpp b/lang/qt/tests/t-keylist.cpp
new file mode 100644
index 0000000..767c96b
--- /dev/null
+++ b/lang/qt/tests/t-keylist.cpp
@@ -0,0 +1,107 @@
+/* t-keylist.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include <QDebug>
+#include <QTest>
+#include <QSignalSpy>
+#include <QMap>
+#include "keylistjob.h"
+#include "qgpgmebackend.h"
+#include "keylistresult.h"
+
+#include "t-support.h"
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class KeyListTest : public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+ void testSingleKeyListSync()
+ {
+ KeyListJob *job = openpgp()->keyListJob(false, false, false);
+ std::vector<GpgME::Key> keys;
+ GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ delete job;
+ Q_ASSERT (!result.error());
+ Q_ASSERT (keys.size() == 1);
+ const QString kId = QLatin1String(keys.front().keyID());
+ Q_ASSERT (kId == QStringLiteral("2D727CC768697734"));
+
+ Q_ASSERT (keys[0].subkeys().size() == 2);
+ Q_ASSERT (keys[0].subkeys()[0].publicKeyAlgorithm() == Subkey::AlgoDSA);
+ Q_ASSERT (keys[0].subkeys()[1].publicKeyAlgorithm() == Subkey::AlgoELG_E);
+ }
+
+ void testPubkeyAlgoAsString()
+ {
+ static const QMap<Subkey::PubkeyAlgo, QString> expected {
+ { Subkey::AlgoRSA, QStringLiteral("RSA") },
+ { Subkey::AlgoRSA_E, QStringLiteral("RSA-E") },
+ { Subkey::AlgoRSA_S, QStringLiteral("RSA-S") },
+ { Subkey::AlgoELG_E, QStringLiteral("ELG-E") },
+ { Subkey::AlgoDSA, QStringLiteral("DSA") },
+ { Subkey::AlgoECC, QStringLiteral("ECC") },
+ { Subkey::AlgoELG, QStringLiteral("ELG") },
+ { Subkey::AlgoECDSA, QStringLiteral("ECDSA") },
+ { Subkey::AlgoECDH, QStringLiteral("ECDH") },
+ { Subkey::AlgoEDDSA, QStringLiteral("EdDSA") },
+ { Subkey::AlgoUnknown, QString() }
+ };
+ Q_FOREACH (Subkey::PubkeyAlgo algo, expected.keys()) {
+ Q_ASSERT(QString::fromUtf8(Subkey::publicKeyAlgorithmAsString(algo)) ==
+ expected.value(algo));
+ }
+ }
+
+ void testKeyListAsync()
+ {
+ KeyListJob *job = openpgp()->keyListJob();
+ connect(job, &KeyListJob::result, job, [this, job](KeyListResult, std::vector<Key> keys, QString, Error)
+ {
+ Q_ASSERT(keys.size() == 1);
+ Q_EMIT asyncDone();
+ });
+ job->start(QStringList() << "alfa@example.net");
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+};
+
+QTEST_MAIN(KeyListTest)
+
+#include "t-keylist.moc"
diff --git a/lang/qt/tests/t-keylocate.cpp b/lang/qt/tests/t-keylocate.cpp
new file mode 100644
index 0000000..e75f24d
--- /dev/null
+++ b/lang/qt/tests/t-keylocate.cpp
@@ -0,0 +1,130 @@
+/* t-keylocate.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include <QDebug>
+#include <QTest>
+#include <QSignalSpy>
+#include <QTemporaryDir>
+#include "keylistjob.h"
+#include "protocol.h"
+#include "keylistresult.h"
+#include "engineinfo.h"
+
+#include "t-support.h"
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class KeyLocateTest : public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+
+#ifdef DO_ONLINE_TESTS
+ void testDaneKeyLocate()
+ {
+ QTemporaryDir dir;
+ const QString oldHome = qgetenv("GNUPGHOME");
+ qputenv("GNUPGHOME", dir.path().toUtf8());
+ /* Could do this with gpgconf but this is not a gpgconf test ;-) */
+ QFile conf(dir.path() + QStringLiteral("/gpg.conf"));
+ Q_ASSERT(conf.open(QIODevice::WriteOnly));
+ conf.write("auto-key-locate dane");
+ conf.close();
+
+ auto *job = openpgp()->locateKeysJob();
+ mTestpattern = QStringLiteral("wk@gnupg.org");
+ connect(job, &KeyListJob::result, job, [this, job](KeyListResult result, std::vector<Key> keys, QString, Error)
+ {
+ Q_ASSERT(!result.error());
+ Q_ASSERT(keys.size() == 1);
+
+ Key k = keys.front();
+ Q_ASSERT(k.numUserIDs());
+ bool found = false;
+ Q_FOREACH (const UserID uid, k.userIDs()) {
+ const QString mailBox = QString::fromUtf8(uid.email());
+ if (mTestpattern.toLower() == mailBox.toLower()) {
+ found = true;
+ }
+ }
+ Q_ASSERT(found);
+ Q_EMIT asyncDone();
+ });
+ job->start(QStringList() << mTestpattern);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ qputenv("GNUPGHOME", oldHome.toUtf8());
+ }
+#endif
+
+ void testKeyLocateSingle()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.10") {
+ return;
+ }
+ auto *job = openpgp()->locateKeysJob();
+ mTestpattern = QStringLiteral("alfa@example.net");
+
+ connect(job, &KeyListJob::result, job, [this, job](KeyListResult result, std::vector<Key> keys, QString, Error)
+ {
+ Q_ASSERT(!result.isNull());
+ Q_ASSERT(!result.isTruncated());
+ Q_ASSERT(!result.error());
+ Q_ASSERT(keys.size() == 1);
+
+ Key k = keys.front();
+ Q_ASSERT(k.numUserIDs());
+ bool found = false;
+ Q_FOREACH (const UserID uid, k.userIDs()) {
+ const QString mailBox = QString::fromUtf8(uid.email());
+ if (mTestpattern.toLower() == mailBox.toLower()) {
+ found = true;
+ }
+ }
+ Q_ASSERT(found);
+ Q_EMIT asyncDone();
+ });
+ job->start(QStringList() << mTestpattern);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+
+private:
+ QString mTestpattern;
+};
+
+QTEST_MAIN(KeyLocateTest)
+
+#include "t-keylocate.moc"
diff --git a/lang/qt/tests/t-ownertrust.cpp b/lang/qt/tests/t-ownertrust.cpp
new file mode 100644
index 0000000..b9efffd
--- /dev/null
+++ b/lang/qt/tests/t-ownertrust.cpp
@@ -0,0 +1,107 @@
+/* t-ownertrust.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include <QDebug>
+#include <QTest>
+#include <QSignalSpy>
+#include "keylistjob.h"
+#include "protocol.h"
+#include "keylistresult.h"
+#include "changeownertrustjob.h"
+
+#include "t-support.h"
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class ChangeOwnerTrustTest: public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+
+ void testChangeOwnerTrust()
+ {
+ KeyListJob *job = openpgp()->keyListJob(false, true, true);
+ std::vector<GpgME::Key> keys;
+ GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ delete job;
+ Q_ASSERT (!result.error());
+ Q_ASSERT (keys.size() == 1);
+ Key key = keys.front();
+ Q_ASSERT (key.ownerTrust() == Key::Unknown);
+
+ ChangeOwnerTrustJob *job2 = openpgp()->changeOwnerTrustJob();
+ connect(job2, &ChangeOwnerTrustJob::result, this, [this](Error e)
+ {
+ if (e) {
+ qDebug() << "Error in result: " << e.asString();
+ }
+ Q_ASSERT(!e);
+ Q_EMIT asyncDone();
+ });
+ job2->start(key, Key::Ultimate);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+
+ job = openpgp()->keyListJob(false, true, true);
+ result = job->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ delete job;
+ key = keys.front();
+ Q_ASSERT (key.ownerTrust() == Key::Ultimate);
+
+ ChangeOwnerTrustJob *job3 = openpgp()->changeOwnerTrustJob();
+ connect(job3, &ChangeOwnerTrustJob::result, this, [this](Error e)
+ {
+ Q_ASSERT(!e);
+ Q_EMIT asyncDone();
+ });
+ job3->start(key, Key::Unknown);
+ Q_ASSERT(spy.wait());
+
+ job = openpgp()->keyListJob(false, true, true);
+ result = job->exec(QStringList() << QStringLiteral("alfa@example.net"),
+ false, keys);
+ delete job;
+
+ key = keys.front();
+ Q_ASSERT (key.ownerTrust() == Key::Unknown);
+ }
+};
+
+QTEST_MAIN(ChangeOwnerTrustTest)
+
+#include "t-ownertrust.moc"
diff --git a/lang/qt/tests/t-support.cpp b/lang/qt/tests/t-support.cpp
new file mode 100644
index 0000000..86372f7
--- /dev/null
+++ b/lang/qt/tests/t-support.cpp
@@ -0,0 +1,95 @@
+/* t-support.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "t-support.h"
+
+#include <QTest>
+
+#include <QProcess>
+#include <QCoreApplication>
+#include <QObject>
+#include <QDir>
+
+void QGpgMETest::initTestCase()
+{
+ const QString gpgHome = qgetenv("GNUPGHOME");
+ QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
+}
+
+void QGpgMETest::cleanupTestCase()
+{
+ QCoreApplication::sendPostedEvents();
+ killAgent();
+}
+
+bool QGpgMETest::copyKeyrings(const QString &src, const QString &dest)
+{
+ bool is21dir = QFileInfo(src + QDir::separator() + QStringLiteral("pubring.kbx")).exists();
+ const QString name = is21dir ? QStringLiteral("pubring.kbx") :
+ QStringLiteral("pubring.gpg");
+ if (!QFile::copy(src + QDir::separator() + name, dest + QDir::separator() + name)) {
+ return false;
+ }
+ if (!is21dir) {
+ return (QFile::copy(src + QDir::separator() + QStringLiteral("secring.gpg"),
+ dest + QDir::separator() + QStringLiteral("secring.gpg")));
+ }
+ QDir dir (src + QDir::separator() + QStringLiteral("private-keys-v1.d"));
+ QDir target(dest);
+ if (!target.mkdir("private-keys-v1.d")) {
+ return false;
+ }
+ foreach (QString f, dir.entryList(QDir::Files)) {
+ if (!QFile::copy(dir.path() + QDir::separator() + f,
+ dest + QDir::separator() +
+ QStringLiteral("private-keys-v1.d") + QDir::separator() + f)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void killAgent(const QString& dir)
+{
+ QProcess proc;
+ proc.setProgram(QStringLiteral("gpg-connect-agent"));
+ QStringList arguments;
+ arguments << "-S " << dir + "/S.gpg-agent";
+ proc.start();
+ proc.waitForStarted();
+ proc.write("KILLAGENT\n");
+ proc.write("BYE\n");
+ proc.closeWriteChannel();
+ proc.waitForFinished();
+}
+
+
+#include "t-support.hmoc"
diff --git a/lang/qt/tests/t-support.h b/lang/qt/tests/t-support.h
new file mode 100644
index 0000000..59d9a4d
--- /dev/null
+++ b/lang/qt/tests/t-support.h
@@ -0,0 +1,63 @@
+/* t-support.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#ifndef T_SUPPORT_H
+#define T_SUPPORT_H
+
+#include "interfaces/passphraseprovider.h"
+#include <QObject>
+
+namespace GpgME
+{
+class TestPassphraseProvider : public PassphraseProvider
+{
+public:
+ char *getPassphrase(const char *useridHint, const char *description,
+ bool previousWasBad, bool &canceled) Q_DECL_OVERRIDE
+ {
+ return strdup("abc");
+ }
+};
+} // namespace GpgME
+
+void killAgent(const QString &dir = qgetenv("GNUPGHOME"));
+
+class QGpgMETest : public QObject
+{
+ Q_OBJECT
+protected:
+ bool copyKeyrings(const QString &from, const QString& to);
+
+public Q_SLOTS:
+ void initTestCase();
+ void cleanupTestCase();
+};
+
+#endif // T_SUPPORT_H
diff --git a/lang/qt/tests/t-tofuinfo.cpp b/lang/qt/tests/t-tofuinfo.cpp
new file mode 100644
index 0000000..d76ff7b
--- /dev/null
+++ b/lang/qt/tests/t-tofuinfo.cpp
@@ -0,0 +1,367 @@
+/* t-tofuinfo.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include <QDebug>
+#include <QTest>
+#include <QTemporaryDir>
+#include "protocol.h"
+#include "tofuinfo.h"
+#include "tofupolicyjob.h"
+#include "verifyopaquejob.h"
+#include "verificationresult.h"
+#include "signingresult.h"
+#include "keylistjob.h"
+#include "keylistresult.h"
+#include "qgpgmesignjob.h"
+#include "key.h"
+#include "t-support.h"
+#include "engineinfo.h"
+#include <iostream>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+static const char testMsg1[] =
+"-----BEGIN PGP MESSAGE-----\n"
+"\n"
+"owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH\n"
+"GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf\n"
+"y1kvP4y+8D5a11ang0udywsA\n"
+"=Crq6\n"
+"-----END PGP MESSAGE-----\n";
+
+class TofuInfoTest: public QGpgMETest
+{
+ Q_OBJECT
+
+ bool testSupported()
+ {
+ return !(GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.16");
+ }
+
+ void testTofuCopy(TofuInfo other, const TofuInfo &orig)
+ {
+ Q_ASSERT(!orig.isNull());
+ Q_ASSERT(!other.isNull());
+ Q_ASSERT(orig.signLast() == other.signLast());
+ Q_ASSERT(orig.signCount() == other.signCount());
+ Q_ASSERT(orig.validity() == other.validity());
+ Q_ASSERT(orig.policy() == other.policy());
+ }
+
+ void signAndVerify(const QString &what, const GpgME::Key &key, int expected)
+ {
+ Context *ctx = Context::createForProtocol(OpenPGP);
+ TestPassphraseProvider provider;
+ ctx->setPassphraseProvider(&provider);
+ ctx->setPinentryMode(Context::PinentryLoopback);
+ auto *job = new QGpgMESignJob(ctx);
+
+ std::vector<Key> keys;
+ keys.push_back(key);
+ QByteArray signedData;
+ auto sigResult = job->exec(keys, what.toUtf8(), NormalSignatureMode, signedData);
+ delete job;
+
+ Q_ASSERT(!sigResult.error());
+ foreach (const auto uid, keys[0].userIDs()) {
+ auto info = uid.tofuInfo();
+ Q_ASSERT(info.signCount() == expected - 1);
+ }
+
+ auto verifyJob = openpgp()->verifyOpaqueJob();
+ QByteArray verified;
+
+ auto result = verifyJob->exec(signedData, verified);
+ delete verifyJob;
+
+ Q_ASSERT(!result.error());
+ Q_ASSERT(verified == what.toUtf8());
+
+ Q_ASSERT(result.numSignatures() == 1);
+ auto sig = result.signatures()[0];
+
+ auto key2 = sig.key();
+ Q_ASSERT(!key.isNull());
+ Q_ASSERT(!strcmp (key2.primaryFingerprint(), key.primaryFingerprint()));
+ Q_ASSERT(!strcmp (key.primaryFingerprint(), sig.fingerprint()));
+ auto stats = key2.userID(0).tofuInfo();
+ Q_ASSERT(!stats.isNull());
+ if (stats.signCount() != expected) {
+ std::cout << "################ Key before verify: "
+ << key
+ << "################ Key after verify: "
+ << key2;
+ }
+ Q_ASSERT(stats.signCount() == expected);
+ }
+
+private Q_SLOTS:
+ void testTofuNull()
+ {
+ if (!testSupported()) {
+ return;
+ }
+ TofuInfo tofu;
+ Q_ASSERT(tofu.isNull());
+ Q_ASSERT(!tofu.description());
+ Q_ASSERT(!tofu.signCount());
+ Q_ASSERT(!tofu.signLast());
+ Q_ASSERT(!tofu.signFirst());
+ Q_ASSERT(tofu.validity() == TofuInfo::ValidityUnknown);
+ Q_ASSERT(tofu.policy() == TofuInfo::PolicyUnknown);
+ }
+
+ void testTofuInfo()
+ {
+ if (!testSupported()) {
+ return;
+ }
+ auto *job = openpgp()->verifyOpaqueJob(true);
+ const QByteArray data1(testMsg1);
+ QByteArray plaintext;
+
+ auto result = job->exec(data1, plaintext);
+ delete job;
+
+ Q_ASSERT(!result.isNull());
+ Q_ASSERT(!result.error());
+ Q_ASSERT(!strcmp(plaintext.constData(), "Just GNU it!\n"));
+
+ Q_ASSERT(result.numSignatures() == 1);
+ Signature sig = result.signatures()[0];
+ /* TOFU is always marginal */
+ Q_ASSERT(sig.validity() == Signature::Marginal);
+
+ auto stats = sig.key().userID(0).tofuInfo();
+ Q_ASSERT(!stats.isNull());
+ Q_ASSERT(sig.key().primaryFingerprint());
+ Q_ASSERT(sig.fingerprint());
+ Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
+ Q_ASSERT(stats.signFirst() == stats.signLast());
+ Q_ASSERT(stats.signCount() == 1);
+ Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
+ Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
+
+ testTofuCopy(stats, stats);
+
+ /* Another verify */
+
+ job = openpgp()->verifyOpaqueJob(true);
+ result = job->exec(data1, plaintext);
+ delete job;
+
+ Q_ASSERT(!result.isNull());
+ Q_ASSERT(!result.error());
+
+ Q_ASSERT(result.numSignatures() == 1);
+ sig = result.signatures()[0];
+ /* TOFU is always marginal */
+ Q_ASSERT(sig.validity() == Signature::Marginal);
+
+ stats = sig.key().userID(0).tofuInfo();
+ Q_ASSERT(!stats.isNull());
+ Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
+ Q_ASSERT(stats.signFirst() == stats.signLast());
+ Q_ASSERT(stats.signCount() == 1);
+ Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
+ Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
+
+ /* Verify that another call yields the same result */
+ job = openpgp()->verifyOpaqueJob(true);
+ result = job->exec(data1, plaintext);
+ delete job;
+
+ Q_ASSERT(!result.isNull());
+ Q_ASSERT(!result.error());
+
+ Q_ASSERT(result.numSignatures() == 1);
+ sig = result.signatures()[0];
+ /* TOFU is always marginal */
+ Q_ASSERT(sig.validity() == Signature::Marginal);
+
+ stats = sig.key().userID(0).tofuInfo();
+ Q_ASSERT(!stats.isNull());
+ Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
+ Q_ASSERT(stats.signFirst() == stats.signLast());
+ Q_ASSERT(stats.signCount() == 1);
+ Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
+ Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
+ }
+
+ void testTofuSignCount()
+ {
+ if (!testSupported()) {
+ return;
+ }
+ auto *job = openpgp()->keyListJob(false, false, false);
+ job->addMode(GpgME::WithTofu);
+ std::vector<GpgME::Key> keys;
+ GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
+ true, keys);
+ delete job;
+ Q_ASSERT(!keys.empty());
+ Key key = keys[0];
+ Q_ASSERT(!key.isNull());
+
+ /* As we sign & verify quickly here we need different
+ * messages to avoid having them treated as the same
+ * message if they were created within the same second.
+ * Alternatively we could use the same message and wait
+ * a second between each call. But this would slow down
+ * the testsuite. */
+ signAndVerify(QStringLiteral("Hello"), key, 1);
+ key.update();
+ signAndVerify(QStringLiteral("Hello2"), key, 2);
+ key.update();
+ signAndVerify(QStringLiteral("Hello3"), key, 3);
+ key.update();
+ signAndVerify(QStringLiteral("Hello4"), key, 4);
+ }
+
+ void testTofuKeyList()
+ {
+ if (!testSupported()) {
+ return;
+ }
+
+ /* First check that the key has no tofu info. */
+ auto *job = openpgp()->keyListJob(false, false, false);
+ std::vector<GpgME::Key> keys;
+ auto result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
+ true, keys);
+ delete job;
+ Q_ASSERT(!keys.empty());
+ auto key = keys[0];
+ Q_ASSERT(!key.isNull());
+ Q_ASSERT(key.userID(0).tofuInfo().isNull());
+ auto keyCopy = key;
+ keyCopy.update();
+ auto sigCnt = keyCopy.userID(0).tofuInfo().signCount();
+ signAndVerify(QStringLiteral("Hello5"), keyCopy,
+ sigCnt + 1);
+ keyCopy.update();
+ signAndVerify(QStringLiteral("Hello6"), keyCopy,
+ sigCnt + 2);
+
+ /* Now another one but with tofu */
+ job = openpgp()->keyListJob(false, false, false);
+ job->addMode(GpgME::WithTofu);
+ result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
+ true, keys);
+ delete job;
+ Q_ASSERT(!result.error());
+ Q_ASSERT(!keys.empty());
+ auto key2 = keys[0];
+ Q_ASSERT(!key2.isNull());
+ auto info = key2.userID(0).tofuInfo();
+ Q_ASSERT(!info.isNull());
+ Q_ASSERT(info.signCount());
+ }
+
+ void testTofuPolicy()
+ {
+ if (!testSupported()) {
+ return;
+ }
+
+ /* First check that the key has no tofu info. */
+ auto *job = openpgp()->keyListJob(false, false, false);
+ std::vector<GpgME::Key> keys;
+ job->addMode(GpgME::WithTofu);
+ auto result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
+ false, keys);
+
+ if (keys.empty()) {
+ qDebug() << "bravo@example.net not found";
+ qDebug() << "Error: " << result.error().asString();
+ const auto homedir = QString::fromLocal8Bit(qgetenv("GNUPGHOME"));
+ qDebug() << "Homedir is: " << homedir;
+ QFileInfo fi(homedir + "/pubring.gpg");
+ qDebug () << "pubring exists: " << fi.exists() << " readable? "
+ << fi.isReadable() << " size: " << fi.size();
+ QFileInfo fi2(homedir + "/pubring.kbx");
+ qDebug () << "keybox exists: " << fi2.exists() << " readable? "
+ << fi2.isReadable() << " size: " << fi2.size();
+
+ result = job->exec(QStringList(), false, keys);
+ foreach (const auto key, keys) {
+ qDebug() << "Key: " << key.userID(0).name() << " <"
+ << key.userID(0).email()
+ << ">\n fpr: " << key.primaryFingerprint();
+ }
+ }
+ Q_ASSERT(!result.error());
+ Q_ASSERT(!keys.empty());
+ auto key = keys[0];
+ Q_ASSERT(!key.isNull());
+ Q_ASSERT(key.userID(0).tofuInfo().policy() != TofuInfo::PolicyBad);
+ auto *tofuJob = openpgp()->tofuPolicyJob();
+ auto err = tofuJob->exec(key, TofuInfo::PolicyBad);
+ Q_ASSERT(!err);
+ result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
+ false, keys);
+ Q_ASSERT(!keys.empty());
+ key = keys[0];
+ Q_ASSERT(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyBad);
+ err = tofuJob->exec(key, TofuInfo::PolicyGood);
+
+ result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
+ false, keys);
+ key = keys[0];
+ Q_ASSERT(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyGood);
+ delete tofuJob;
+ delete job;
+ }
+
+ void initTestCase()
+ {
+ QGpgMETest::initTestCase();
+ const QString gpgHome = qgetenv("GNUPGHOME");
+ qputenv("GNUPGHOME", mDir.path().toUtf8());
+ Q_ASSERT(mDir.isValid());
+ QFile conf(mDir.path() + QStringLiteral("/gpg.conf"));
+ Q_ASSERT(conf.open(QIODevice::WriteOnly));
+ conf.write("trust-model tofu+pgp");
+ conf.close();
+ QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
+ Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+ agentConf.write("allow-loopback-pinentry");
+ agentConf.close();
+ Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
+ }
+private:
+ QTemporaryDir mDir;
+
+};
+
+QTEST_MAIN(TofuInfoTest)
+
+#include "t-tofuinfo.moc"
diff --git a/lang/qt/tests/t-wkspublish.cpp b/lang/qt/tests/t-wkspublish.cpp
new file mode 100644
index 0000000..17d3447
--- /dev/null
+++ b/lang/qt/tests/t-wkspublish.cpp
@@ -0,0 +1,278 @@
+/* t-wkspublish.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2016 Intevation GmbH
+
+ QGpgME is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ QGpgME is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+#include <QDebug>
+#include <QTest>
+#include <QSignalSpy>
+#include <QTemporaryDir>
+#include "wkspublishjob.h"
+#include "keygenerationjob.h"
+#include "keygenerationresult.h"
+#include "importjob.h"
+#include "importresult.h"
+#include "protocol.h"
+#include "engineinfo.h"
+
+#include "t-support.h"
+
+using namespace QGpgME;
+using namespace GpgME;
+
+//#define DO_ONLINE_TESTS
+
+#define TEST_ADDRESS "testuser2@test.gnupg.org"
+
+static const char *testSecKey =
+"-----BEGIN PGP PRIVATE KEY BLOCK-----\n"
+"\n"
+"lHgEV77hVhMJKyQDAwIIAQEHAgMEN3qKqBr9EecnfUnpw8RS8DHAjJqhwm2HAoEE\n"
+"3yfQQ9w8uB/bKm5dqW4HML3JWRH8YoJaKSVrJY2D1FZUY+vHlgABAKDwEAB0HND8\n"
+"5kbxiJmqKIuuNqCJ2jHgs9G0xk4GdKvZEdq0JlRlc3QgVXNlciAyIDx0ZXN0dXNl\n"
+"cjJAdGVzdC5nbnVwZy5vcmc+iHkEExMIACEFAle+4VYCGwMFCwkIBwIGFQgJCgsC\n"
+"BBYCAwECHgECF4AACgkQRVRoUEJO+6zgFQD7BF3pnS3w3A7J9y+Y3kyGfmscXFWJ\n"
+"Kme1PAsAlVSm1y4A+weReMvWFYHJH257v94yhStmV8egGoybsNDttNAW53cbnHwE\n"
+"V77hVhIJKyQDAwIIAQEHAgMEX+6cF0HEn4g3ztFvwHyr7uwXMVYUGL3lE3mjhnV3\n"
+"SbY6Dmy3OeFVnEVkawHqSv+HobpQTeEqNoQHAoIiXFCRlgMBCAcAAP9FykiyDspm\n"
+"T33XWRPD+LAOmaIU7CIhfv9+lVkeExlU1w+qiGEEGBMIAAkFAle+4VYCGwwACgkQ\n"
+"RVRoUEJO+6xjhgD/ZJ/MwYZJPk/xPYhTP8+wF+tErVNA8w3pP9D69dgUPdcA/izZ\n"
+"Pji6YetVhgsyaHc4PrKynsk5G6nM3KkAOehUQsX8\n"
+"=S/Wa\n"
+"-----END PGP PRIVATE KEY BLOCK-----\n";
+
+static const char *testResponse =
+"From key-submission@test.gnupg.org Thu Aug 25 12:15:54 2016\n"
+"Return-Path: <webkey@g10code.com>\n"
+"From: key-submission@test.gnupg.org\n"
+"To: testuser2@test.gnupg.org\n"
+"Subject: Confirm your key publication\n"
+"X-Wks-Loop: webkey.g10code.com\n"
+"MIME-Version: 1.0\n"
+"Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\";\n"
+" boundary=\"=-=01-wbu5fr9nu6fix5tcojjo=-=\"\n"
+"Date: Thu, 25 Aug 2016 12:15:54 +0000\n"
+"Message-Id: <E1bctZa-0004LE-Fr@kerckhoffs.g10code.com>\n"
+"Sender: <webkey@g10code.com>\n"
+"X-Kolab-Scheduling-Message: FALSE\n"
+"\n"
+" \n"
+"\n"
+"--=-=01-wbu5fr9nu6fix5tcojjo=-=\n"
+"Content-Type: application/pgp-encrypted\n"
+"\n"
+"Version: 1\n"
+"\n"
+"--=-=01-wbu5fr9nu6fix5tcojjo=-=\n"
+"Content-Type: application/octet-stream\n"
+"\n"
+"-----BEGIN PGP MESSAGE-----\n"
+"Version: GnuPG v2\n"
+"\n"
+"hH4D8pSp7hUsFUASAgMEg0w39E6d0TkFYxLbT6n3YcoKTT+Ur/c7Sn1ECyL7Rnuk\n"
+"cmPO0adt3JxueK7Oz5COlk32SECFODdF3cQuDhkGxzC6Sfc4SfisdILmNhaT/MeW\n"
+"8a+yE4skSK70absif4kw5XkvxXNxHeIHfAteP50jPJLSwEsBTEceb9cRMoP7s8w0\n"
+"lYyi+RWQ7UKlKKywtcRCL4ow2H7spjx+a+3FzNOAoy7K0/thhLVRk8z+iuPi0/4n\n"
+"Z2Ql60USLLUlfV2ZIpXdCd+5GjTJsnGhDos1pas5TZcOOAxO12Cg5TcqHISOaqa8\n"
+"6BqxcKCU3NypIynOKHj375KArSs0WsEH8HWHyBBHB+NYtNpnTAuHNKxM+JtNxf+U\n"
+"NfD2zptS6kyiHLw+4zjL5pEV7RHS2PBwWBDS6vhnyybNwckleya96U04iYiGRYGE\n"
+"lUUR6Fl8H6x04dItFH1/jJA6Ppcu4FoYou04HADWCqJXPTgztjiW1/9QoCeXl5lm\n"
+"CcOCcuw7lXp+qTejuns=\n"
+"=SsWX\n"
+"-----END PGP MESSAGE-----\n"
+"\n"
+"--=-=01-wbu5fr9nu6fix5tcojjo=-=--\n";
+
+
+class WKSPublishTest : public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+ void testUnsupported()
+ {
+ // First check if it is supported
+ auto job = openpgp()->wksPublishJob();
+ connect(job, &WKSPublishJob::result, this,
+ [this] (Error err, QByteArray out, QByteArray errout, QString, Error) {
+ Q_ASSERT(err);
+ Q_EMIT asyncDone();
+ });
+ job->startCheck ("testuser1@localhost");
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+#ifdef DO_ONLINE_TESTS
+private Q_SLOTS:
+#else
+private:
+#endif
+ void testWSKPublishSupport()
+ {
+ // First check if it is supported
+ auto job = openpgp()->wksPublishJob();
+ connect(job, &WKSPublishJob::result, this,
+ [this] (Error err, QByteArray out, QByteArray errout, QString, Error) {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") {
+ std::cout << err;
+ Q_ASSERT(err);
+ } else {
+ Q_ASSERT(!err);
+ }
+ Q_EMIT asyncDone();
+ });
+ job->startCheck ("testuser1@test.gnupg.org");
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+
+ void testWKSPublishErrors() {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") {
+ /* Not supported */
+ return;
+ }
+ auto job = openpgp()->wksPublishJob();
+ connect(job, &WKSPublishJob::result, this,
+ [this] (Error err, QByteArray out, QByteArray errout, QString, Error) {
+ Q_ASSERT(err);
+ Q_EMIT asyncDone();
+ });
+ job->startCreate("AB874F24E98EBB8487EE7B170F8E3D97FE7011B7",
+ QStringLiteral("Foo@bar.baz"));
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+ }
+
+ void testWKSPublishCreate() {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") {
+ /* Not supported */
+ return;
+ }
+ /* First generate a test key */
+ const QString args = QStringLiteral("<GnupgKeyParms format=\"internal\">\n"
+ "%no-protection\n"
+ "%transient-key\n"
+ "key-type: ECDSA\n"
+ "key-curve: brainpoolP256r1\n"
+ "key-usage: sign\n"
+ "subkey-type: ECDH\n"
+ "subkey-curve: brainpoolP256r1\n"
+ "subkey-usage: encrypt\n"
+ "name-email: %1\n"
+ "name-real: Test User\n"
+ "</GnupgKeyParms>").arg(TEST_ADDRESS);
+
+ auto keygenjob = openpgp()->keyGenerationJob();
+ QByteArray fpr;
+ connect(keygenjob, &KeyGenerationJob::result, this,
+ [this, &fpr](KeyGenerationResult result, QByteArray pubkeyData, QString, Error)
+ {
+ Q_ASSERT(!result.error());
+ fpr = QByteArray(result.fingerprint());
+ Q_ASSERT(!fpr.isEmpty());
+ Q_EMIT asyncDone();
+ });
+ keygenjob->start(args);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+
+ /* Then try to create a request. */
+ auto job = openpgp()->wksPublishJob();
+ connect(job, &WKSPublishJob::result, this,
+ [this] (Error err, QByteArray out, QByteArray errout, QString, Error) {
+ Q_ASSERT(!err);
+ Q_EMIT asyncDone();
+ const QString outstr = QString(out);
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("-----BEGIN PGP PUBLIC KEY BLOCK-----")));
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("Content-Type: application/pgp-keys")));
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("From: " TEST_ADDRESS)));
+ });
+ job->startCreate(fpr.constData(), QLatin1String(TEST_ADDRESS));
+ Q_ASSERT(spy.wait());
+ }
+
+ void testWKSPublishRecieve() {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") {
+ /* Not supported */
+ return;
+ }
+ auto importjob = openpgp()->importJob();
+ connect(importjob, &ImportJob::result, this,
+ [this](ImportResult result, QString, Error)
+ {
+ Q_ASSERT(!result.error());
+ Q_ASSERT(!result.imports().empty());
+ Q_ASSERT(result.numSecretKeysImported());
+ Q_EMIT asyncDone();
+ });
+ importjob->start(QByteArray(testSecKey));
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ Q_ASSERT(spy.wait());
+
+ /* Get a response. */
+ auto job = openpgp()->wksPublishJob();
+ connect(job, &WKSPublishJob::result, this,
+ [this] (Error err, QByteArray out, QByteArray errout, QString, Error) {
+ Q_ASSERT(!err);
+ Q_EMIT asyncDone();
+ const QString outstr = QString(out);
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("-----BEGIN PGP MESSAGE-----")));
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("Content-Type: multipart/encrypted;")));
+ Q_ASSERT(outstr.contains(
+ QStringLiteral("From: " TEST_ADDRESS)));
+ });
+ job->startRecieve(QByteArray(testResponse));
+ Q_ASSERT(spy.wait());
+ }
+
+ void initTestCase()
+ {
+ QGpgMETest::initTestCase();
+ const QString gpgHome = qgetenv("GNUPGHOME");
+ qputenv("GNUPGHOME", mDir.path().toUtf8());
+ Q_ASSERT(mDir.isValid());
+ QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
+ Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+ agentConf.write("allow-loopback-pinentry");
+ agentConf.close();
+ }
+private:
+ QTemporaryDir mDir;
+};
+
+QTEST_MAIN(WKSPublishTest)
+
+#include "t-wkspublish.moc"