[Pkg-gnupg-commit] [gpgme] 40/412: Add QGpgME code from libkleo

Daniel Kahn Gillmor dkg at fifthhorseman.net
Thu Sep 22 21:26:10 UTC 2016


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

dkg pushed a commit to branch master
in repository gpgme.

commit 226e51052ae73efa8d9f30729b28de68d35231af
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Sat Apr 2 04:31:59 2016 -0800

    Add QGpgME code from libkleo
    
    * lang/qt/src/Makefile.am,
    lang/qt/src/abstractimportjob.h,
    lang/qt/src/adduseridjob.h,
    lang/qt/src/changeexpiryjob.h,
    lang/qt/src/changeownertrustjob.h,
    lang/qt/src/changepasswdjob.h,
    lang/qt/src/cryptoconfig.h,
    lang/qt/src/decryptjob.h,
    lang/qt/src/decryptverifyjob.h,
    lang/qt/src/deletejob.h,
    lang/qt/src/downloadjob.h,
    lang/qt/src/encryptjob.h,
    lang/qt/src/exportjob.h,
    lang/qt/src/hierarchicalkeylistjob.h,
    lang/qt/src/importfromkeyserverjob.h,
    lang/qt/src/importjob.h,
    lang/qt/src/job.cpp,
    lang/qt/src/job.h,
    lang/qt/src/keygenerationjob.h,
    lang/qt/src/keylistjob.h,
    lang/qt/src/listallkeysjob.h,
    lang/qt/src/multideletejob.h,
    lang/qt/src/qgpgmeadduseridjob.cpp,
    lang/qt/src/qgpgmeadduseridjob.h,
    lang/qt/src/qgpgmebackend.cpp,
    lang/qt/src/qgpgmebackend.h,
    lang/qt/src/qgpgmechangeexpiryjob.cpp,
    lang/qt/src/qgpgmechangeexpiryjob.h,
    lang/qt/src/qgpgmechangeownertrustjob.cpp,
    lang/qt/src/qgpgmechangeownertrustjob.h,
    lang/qt/src/qgpgmechangepasswdjob.cpp,
    lang/qt/src/qgpgmechangepasswdjob.h,
    lang/qt/src/qgpgmecryptoconfig.cpp,
    lang/qt/src/qgpgmecryptoconfig.h,
    lang/qt/src/qgpgmedecryptjob.cpp,
    lang/qt/src/qgpgmedecryptjob.h,
    lang/qt/src/qgpgmedecryptverifyjob.cpp,
    lang/qt/src/qgpgmedecryptverifyjob.h,
    lang/qt/src/qgpgmedeletejob.cpp,
    lang/qt/src/qgpgmedeletejob.h,
    lang/qt/src/qgpgmedownloadjob.cpp,
    lang/qt/src/qgpgmedownloadjob.h,
    lang/qt/src/qgpgmeencryptjob.cpp,
    lang/qt/src/qgpgmeencryptjob.h,
    lang/qt/src/qgpgmeexportjob.cpp,
    lang/qt/src/qgpgmeexportjob.h,
    lang/qt/src/qgpgmeimportfromkeyserverjob.cpp,
    lang/qt/src/qgpgmeimportfromkeyserverjob.h,
    lang/qt/src/qgpgmeimportjob.cpp,
    lang/qt/src/qgpgmeimportjob.h,
    lang/qt/src/qgpgmekeygenerationjob.cpp,
    lang/qt/src/qgpgmekeygenerationjob.h,
    lang/qt/src/qgpgmekeylistjob.cpp,
    lang/qt/src/qgpgmekeylistjob.h,
    lang/qt/src/qgpgmelistallkeysjob.cpp,
    lang/qt/src/qgpgmelistallkeysjob.h,
    lang/qt/src/qgpgmenewcryptoconfig.cpp,
    lang/qt/src/qgpgmenewcryptoconfig.h,
    lang/qt/src/qgpgmerefreshkeysjob.cpp,
    lang/qt/src/qgpgmerefreshkeysjob.h,
    lang/qt/src/qgpgmesecretkeyexportjob.cpp,
    lang/qt/src/qgpgmesecretkeyexportjob.h,
    lang/qt/src/qgpgmesignencryptjob.cpp,
    lang/qt/src/qgpgmesignencryptjob.h,
    lang/qt/src/qgpgmesignjob.cpp,
    lang/qt/src/qgpgmesignjob.h,
    lang/qt/src/qgpgmesignkeyjob.cpp,
    lang/qt/src/qgpgmesignkeyjob.h,
    lang/qt/src/qgpgmeverifydetachedjob.cpp,
    lang/qt/src/qgpgmeverifydetachedjob.h,
    lang/qt/src/qgpgmeverifyopaquejob.cpp,
    lang/qt/src/qgpgmeverifyopaquejob.h,
    lang/qt/src/refreshkeysjob.h,
    lang/qt/src/signencryptjob.h,
    lang/qt/src/signjob.h,
    lang/qt/src/signkeyjob.h,
    lang/qt/src/specialjob.h,
    lang/qt/src/threadedjobmixin.cpp,
    lang/qt/src/threadedjobmixin.h,
    lang/qt/src/verifydetachedjob.h,
    lang/qt/src/verifyopaquejob.h: New.
    * lang/qt/src/Makefile.am:
    
    --
    The ShowErrorMessage calls were removed and are to be replaced
    by error signals / error status which the UI should then handle.
    
    This allowed to port away from KMessageBox and KLocalizedstring.
    
    Additionally this removed the old process bases qgpgmeconfigdialog,
    and GnuPGProcessBase. Classes using GnuPGProcessbase were changed
    to KProcess api.
    
    This is a first compiling version. API is subject to change to
    resolve the split between base jobs and qgpgme classes.
---
 lang/qt/src/Makefile.am                      | 130 +++-
 lang/qt/src/abstractimportjob.h              |  62 ++
 lang/qt/src/adduseridjob.h                   |  84 +++
 lang/qt/src/changeexpiryjob.h                |  84 +++
 lang/qt/src/changeownertrustjob.h            |  81 +++
 lang/qt/src/changepasswdjob.h                |  82 +++
 lang/qt/src/cryptoconfig.h                   | 399 +++++++++++
 lang/qt/src/dataprovider.cpp                 |   1 +
 lang/qt/src/dataprovider.h                   |   1 +
 lang/qt/src/decryptjob.h                     | 100 +++
 lang/qt/src/decryptverifyjob.h               | 105 +++
 lang/qt/src/deletejob.h                      |  82 +++
 lang/qt/src/downloadjob.h                    | 106 +++
 lang/qt/src/encryptjob.h                     | 120 ++++
 lang/qt/src/exportjob.h                      |  86 +++
 lang/qt/src/hierarchicalkeylistjob.h         | 125 ++++
 lang/qt/src/importfromkeyserverjob.h         |  83 +++
 lang/qt/src/importjob.h                      |  82 +++
 lang/qt/src/job.cpp                          | 150 +++++
 lang/qt/src/job.h                            |  94 +++
 lang/qt/src/keygenerationjob.h               |  84 +++
 lang/qt/src/keylistjob.h                     | 105 +++
 lang/qt/src/listallkeysjob.h                 | 103 +++
 lang/qt/src/multideletejob.h                 | 107 +++
 lang/qt/src/qgpgmeadduseridjob.cpp           |  82 +++
 lang/qt/src/qgpgmeadduseridjob.h             |  65 ++
 lang/qt/src/qgpgmebackend.cpp                | 515 +++++++++++++++
 lang/qt/src/qgpgmebackend.h                  | 152 +++++
 lang/qt/src/qgpgmechangeexpiryjob.cpp        |  81 +++
 lang/qt/src/qgpgmechangeexpiryjob.h          |  66 ++
 lang/qt/src/qgpgmechangeownertrustjob.cpp    |  77 +++
 lang/qt/src/qgpgmechangeownertrustjob.h      |  65 ++
 lang/qt/src/qgpgmechangepasswdjob.cpp        |  78 +++
 lang/qt/src/qgpgmechangepasswdjob.h          |  66 ++
 lang/qt/src/qgpgmecryptoconfig.cpp           | 948 +++++++++++++++++++++++++++
 lang/qt/src/qgpgmecryptoconfig.h             | 245 +++++++
 lang/qt/src/qgpgmedecryptjob.cpp             | 127 ++++
 lang/qt/src/qgpgmedecryptjob.h               |  84 +++
 lang/qt/src/qgpgmedecryptverifyjob.cpp       | 135 ++++
 lang/qt/src/qgpgmedecryptverifyjob.h         |  89 +++
 lang/qt/src/qgpgmedeletejob.cpp              |  65 ++
 lang/qt/src/qgpgmedeletejob.h                |  71 ++
 lang/qt/src/qgpgmedownloadjob.cpp            | 102 +++
 lang/qt/src/qgpgmedownloadjob.h              |  69 ++
 lang/qt/src/qgpgmeencryptjob.cpp             | 161 +++++
 lang/qt/src/qgpgmeencryptjob.h               | 102 +++
 lang/qt/src/qgpgmeexportjob.cpp              |  76 +++
 lang/qt/src/qgpgmeexportjob.h                |  66 ++
 lang/qt/src/qgpgmeimportfromkeyserverjob.cpp |  82 +++
 lang/qt/src/qgpgmeimportfromkeyserverjob.h   |  81 +++
 lang/qt/src/qgpgmeimportjob.cpp              |  85 +++
 lang/qt/src/qgpgmeimportjob.h                |  81 +++
 lang/qt/src/qgpgmekeygenerationjob.cpp       |  71 ++
 lang/qt/src/qgpgmekeygenerationjob.h         |  72 ++
 lang/qt/src/qgpgmekeylistjob.cpp             | 167 +++++
 lang/qt/src/qgpgmekeylistjob.h               |  90 +++
 lang/qt/src/qgpgmelistallkeysjob.cpp         | 170 +++++
 lang/qt/src/qgpgmelistallkeysjob.h           |  86 +++
 lang/qt/src/qgpgmenewcryptoconfig.cpp        | 742 +++++++++++++++++++++
 lang/qt/src/qgpgmenewcryptoconfig.h          | 192 ++++++
 lang/qt/src/qgpgmerefreshkeysjob.cpp         | 224 +++++++
 lang/qt/src/qgpgmerefreshkeysjob.h           |  79 +++
 lang/qt/src/qgpgmesecretkeyexportjob.cpp     | 141 ++++
 lang/qt/src/qgpgmesecretkeyexportjob.h       |  81 +++
 lang/qt/src/qgpgmesignencryptjob.cpp         | 160 +++++
 lang/qt/src/qgpgmesignencryptjob.h           | 109 +++
 lang/qt/src/qgpgmesignjob.cpp                | 164 +++++
 lang/qt/src/qgpgmesignjob.h                  | 101 +++
 lang/qt/src/qgpgmesignkeyjob.cpp             | 127 ++++
 lang/qt/src/qgpgmesignkeyjob.h               |  94 +++
 lang/qt/src/qgpgmeverifydetachedjob.cpp      | 119 ++++
 lang/qt/src/qgpgmeverifydetachedjob.h        |  85 +++
 lang/qt/src/qgpgmeverifyopaquejob.cpp        | 126 ++++
 lang/qt/src/qgpgmeverifyopaquejob.h          |  84 +++
 lang/qt/src/refreshkeysjob.h                 |  93 +++
 lang/qt/src/signencryptjob.h                 | 136 ++++
 lang/qt/src/signjob.h                        | 122 ++++
 lang/qt/src/signkeyjob.h                     | 117 ++++
 lang/qt/src/specialjob.h                     |  90 +++
 lang/qt/src/threadedjobmixin.cpp             | 112 ++++
 lang/qt/src/threadedjobmixin.h               | 280 ++++++++
 lang/qt/src/verifydetachedjob.h              |  98 +++
 lang/qt/src/verifyopaquejob.h                | 101 +++
 83 files changed, 10802 insertions(+), 3 deletions(-)

diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am
index 54d0530..a3f99a0 100644
--- a/lang/qt/src/Makefile.am
+++ b/lang/qt/src/Makefile.am
@@ -18,13 +18,128 @@
 # 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
+EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in \
+             gpgme_backend_debug.h
 
 qgpgme_sources = \
-    dataprovider.cpp
+    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 \
+    gpgme_backend_debug.cpp
 
 qgpgme_headers = \
-    dataprovider.h qgpgme_export.h
+    qgpgme_export.h \
+    abstractimportjob.h \
+    adduseridjob.h \
+    changeexpiryjob.h \
+    changeownertrustjob.h \
+    changepasswdjob.h \
+    cryptoconfig.h \
+    dataprovider.h \
+    decryptjob.h \
+    decryptverifyjob.h \
+    deletejob.h \
+    downloadjob.h \
+    encryptjob.h \
+    exportjob.h \
+    hierarchicalkeylistjob.h \
+    importfromkeyserverjob.h \
+    importjob.h \
+    job.h \
+    keygenerationjob.h \
+    keylistjob.h \
+    listallkeysjob.h \
+    multideletejob.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 \
+    qgpgmenewcryptoconfig.h \
+    qgpgmerefreshkeysjob.h \
+    qgpgmesecretkeyexportjob.h \
+    qgpgmesignencryptjob.h \
+    qgpgmesignjob.h \
+    qgpgmesignkeyjob.h \
+    qgpgmeverifydetachedjob.h \
+    qgpgmeverifyopaquejob.h \
+    refreshkeysjob.h \
+    signencryptjob.h \
+    signjob.h \
+    signkeyjob.h \
+    specialjob.h \
+    threadedjobmixin.h \
+    verifydetachedjob.h \
+    verifyopaquejob.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 \
+    refreshkeysjob.moc \
+    signencryptjob.moc \
+    signjob.moc \
+    signkeyjob.moc \
+    specialjob.moc \
+    verifydetachedjob.moc \
+    verifyopaquejob.moc
 
 qgpgmeincludedir = $(includedir)/qgpgme
 qgpgmeinclude_HEADERS = $(qgpgme_headers)
@@ -65,3 +180,12 @@ uninstall-cmake-files:
 install-data-local: install-cmake-files
 
 uninstall-local: uninstall-cmake-files
+
+BUILT_SOURCES = $(qgpgme_moc_sources)
+
+CLEANFILES = $(qgpgme_moc_sources)
+
+nodist_qgpgme_SOURCES = $(qgpgme_moc_sources)
+
+.h.moc:
+	$(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
diff --git a/lang/qt/src/abstractimportjob.h b/lang/qt/src/abstractimportjob.h
new file mode 100644
index 0000000..662fed8
--- /dev/null
+++ b/lang/qt/src/abstractimportjob.h
@@ -0,0 +1,62 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+namespace GpgME
+{
+class Error;
+class ImportResult;
+}
+
+namespace QGpgME
+{
+
+class 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..8ffd962
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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..f1a3881
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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..f42fa05
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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..eb9ab0f
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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..1ab2ccf
--- /dev/null
+++ b/lang/qt/src/cryptoconfig.h
@@ -0,0 +1,399 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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
+
+#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 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 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 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 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
index 8893877..9cb5a64 100644
--- a/lang/qt/src/dataprovider.cpp
+++ b/lang/qt/src/dataprovider.cpp
@@ -1,5 +1,6 @@
 /* dataprovider.cpp
    Copyright (C) 2004 Klar�vdalens Datakonsult AB
+    Copyright (c) 2016 Intevation GmbH
 
    This file is part of QGPGME.
 
diff --git a/lang/qt/src/dataprovider.h b/lang/qt/src/dataprovider.h
index 8bc0c85..5df4fc2 100644
--- a/lang/qt/src/dataprovider.h
+++ b/lang/qt/src/dataprovider.h
@@ -1,5 +1,6 @@
 /* dataprovider.h
    Copyright (C) 2004 Klarälvdalens Datakonsult AB
+    Copyright (c) 2016 Intevation GmbH
 
    This file is part of QGPGME.
 
diff --git a/lang/qt/src/decryptjob.h b/lang/qt/src/decryptjob.h
new file mode 100644
index 0000000..e201276
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+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 boost::shared_ptr<QIODevice> &cipherText, const boost::shared_ptr<QIODevice> &plainText = boost::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..fc51a20
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+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 boost::shared_ptr<QIODevice> &cipherText, const boost::shared_ptr<QIODevice> &plainText = boost::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/deletejob.h b/lang/qt/src/deletejob.h
new file mode 100644
index 0000000..5249960
--- /dev/null
+++ b/lang/qt/src/deletejob.h
@@ -0,0 +1,82 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 "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 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..4c1ee98
--- /dev/null
+++ b/lang/qt/src/downloadjob.h
@@ -0,0 +1,106 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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>
+
+namespace GpgME
+{
+class Error;
+}
+
+namespace boost
+{
+template <typename T> class shared_ptr;
+}
+
+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 boost::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..91ad5e6
--- /dev/null
+++ b/lang/qt/src/encryptjob.h
@@ -0,0 +1,120 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+#include <vector>
+
+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 boost::shared_ptr<QIODevice> &plainText,
+                       const boost::shared_ptr<QIODevice> &cipherText = boost::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;
+
+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..2cc3d06
--- /dev/null
+++ b/lang/qt/src/exportjob.h
@@ -0,0 +1,86 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 "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 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/hierarchicalkeylistjob.h b/lang/qt/src/hierarchicalkeylistjob.h
new file mode 100644
index 0000000..63aea6b
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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);
+    /*! \reimp 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..873ce51
--- /dev/null
+++ b/lang/qt/src/importfromkeyserverjob.h
@@ -0,0 +1,83 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+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 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..e72ef4c
--- /dev/null
+++ b/lang/qt/src/importjob.h
@@ -0,0 +1,82 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <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 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..abbe16f
--- /dev/null
+++ b/lang/qt/src/job.cpp
@@ -0,0 +1,150 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <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)
+
+#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"
diff --git a/lang/qt/src/job.h b/lang/qt/src/job.h
new file mode 100644
index 0000000..caa840b
--- /dev/null
+++ b/lang/qt/src/job.h
@@ -0,0 +1,94 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 void showErrorDialog(QWidget *parent = Q_NULLPTR, const QString &caption = QString()) const;
+
+    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/keygenerationjob.h b/lang/qt/src/keygenerationjob.h
new file mode 100644
index 0000000..43e0941
--- /dev/null
+++ b/lang/qt/src/keygenerationjob.h
@@ -0,0 +1,84 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <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 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..76f9a85
--- /dev/null
+++ b/lang/qt/src/keylistjob.h
@@ -0,0 +1,105 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+#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 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;
+
+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..c662c04
--- /dev/null
+++ b/lang/qt/src/listallkeysjob.h
@@ -0,0 +1,103 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+#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 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..a142f32
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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);
+
+    /*! \reimp 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/qgpgmeadduseridjob.cpp b/lang/qt/src/qgpgmeadduseridjob.cpp
new file mode 100644
index 0000000..19127a8
--- /dev/null
+++ b/lang/qt/src/qgpgmeadduseridjob.cpp
@@ -0,0 +1,82 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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)
+{
+
+    std::auto_ptr<GpgAddUserIDEditInteractor> gau(new GpgAddUserIDEditInteractor);
+
+    gau->setNameUtf8(name.toUtf8().constData());
+    gau->setEmailUtf8(email.toUtf8().constData());
+    gau->setCommentUtf8(comment.toUtf8().constData());
+
+    std::auto_ptr<EditInteractor> ei(gau);
+
+    QGpgME::QByteArrayDataProvider dp;
+    Data data(&dp);
+    assert(!data.isNull());
+    const Error err = ctx->edit(key, ei, data);
+    Error ae;
+    const QString log = _detail::audit_log_as_html(ctx, ae);
+    return make_tuple(err, log, ae);
+}
+
+Error QGpgMEAddUserIDJob::start(const Key &key, const QString &name, const QString &email, const QString &comment)
+{
+    run(bind(&add_user_id, _1, key, name, email, comment));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmeadduseridjob.h b/lang/qt/src/qgpgmeadduseridjob.h
new file mode 100644
index 0000000..ce26ad4
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp 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..ac77124
--- /dev/null
+++ b/lang/qt/src/qgpgmebackend.cpp
@@ -0,0 +1,515 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 "qgpgmecryptoconfig.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 "error.h"
+#include "engineinfo.h"
+
+#include <QFile>
+#include <QString>
+
+const char QGpgME::QGpgMEBackend::OpenPGP[] = "OpenPGP";
+const char QGpgME::QGpgMEBackend::SMIME[] = "SMIME";
+
+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::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) {
+#ifdef _WIN32_WCE // for now...
+        if (GpgME::hasFeature(GpgME::GpgConfEngineFeature, 0)) {
+            mCryptoConfig = new QGpgMENewCryptoConfig;
+        } else
+#endif
+            if (!QGpgMECryptoConfig::gpgConfPath().isEmpty()) {
+                mCryptoConfig = new QGpgMECryptoConfig();
+            }
+    }
+    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;
+    }
+}
diff --git a/lang/qt/src/qgpgmebackend.h b/lang/qt/src/qgpgmebackend.h
new file mode 100644
index 0000000..962a4d9
--- /dev/null
+++ b/lang/qt/src/qgpgmebackend.h
@@ -0,0 +1,152 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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>
+
+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 QString;
+class QVariant;
+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;
+};
+
+class 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;
+    virtual ChangeOwnerTrustJob *changeOwnerTrustJob() const;
+    virtual ChangePasswdJob      *changePasswdJob() const;
+    virtual SignKeyJob           *signKeyJob() const;
+    virtual AddUserIDJob         *addUserIDJob() const;
+    virtual SpecialJob           *specialJob(const char *type, const QMap<QString, QVariant> &args) const = 0;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEBACKEND_H__
diff --git a/lang/qt/src/qgpgmechangeexpiryjob.cpp b/lang/qt/src/qgpgmechangeexpiryjob.cpp
new file mode 100644
index 0000000..ac06d8d
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeexpiryjob.cpp
@@ -0,0 +1,81 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+QGpgMEChangeExpiryJob::QGpgMEChangeExpiryJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEChangeExpiryJob::~QGpgMEChangeExpiryJob() {}
+
+static QGpgMEChangeExpiryJob::result_type change_expiry(Context *ctx, const Key &key, const QDateTime &expiry)
+{
+    std::auto_ptr<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, ei, data);
+    Error ae;
+    const QString log = _detail::audit_log_as_html(ctx, ae);
+    return make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangeExpiryJob::start(const Key &key, const QDateTime &expiry)
+{
+    run(bind(&change_expiry, _1, key, expiry));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmechangeexpiryjob.h b/lang/qt/src/qgpgmechangeexpiryjob.h
new file mode 100644
index 0000000..3ba140b
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp 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..3e4144d
--- /dev/null
+++ b/lang/qt/src/qgpgmechangeownertrustjob.cpp
@@ -0,0 +1,77 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+QGpgMEChangeOwnerTrustJob::QGpgMEChangeOwnerTrustJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEChangeOwnerTrustJob::~QGpgMEChangeOwnerTrustJob() {}
+
+static QGpgMEChangeOwnerTrustJob::result_type change_ownertrust(Context *ctx, const Key &key, Key::OwnerTrust trust)
+{
+    std::auto_ptr<EditInteractor>
+    ei(new GpgSetOwnerTrustEditInteractor(trust));
+
+    QGpgME::QByteArrayDataProvider dp;
+    Data data(&dp);
+    assert(!data.isNull());
+
+    const Error err = ctx->edit(key, ei, data);
+    Error ae;
+    const QString log = _detail::audit_log_as_html(ctx, ae);
+    return make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangeOwnerTrustJob::start(const Key &key, Key::OwnerTrust trust)
+{
+    run(bind(&change_ownertrust, _1, key, trust));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmechangeownertrustjob.h b/lang/qt/src/qgpgmechangeownertrustjob.h
new file mode 100644
index 0000000..4cf4f72
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp 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..4e5f6e3
--- /dev/null
+++ b/lang/qt/src/qgpgmechangepasswdjob.cpp
@@ -0,0 +1,78 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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::auto_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 make_tuple(err, log, ae);
+}
+
+Error QGpgMEChangePasswdJob::start(const Key &key)
+{
+    run(bind(&change_passwd, _1, key));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmechangepasswdjob.h b/lang/qt/src/qgpgmechangepasswdjob.h
new file mode 100644
index 0000000..b799c20
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp from ChangePasswdJob */
+    GpgME::Error start(const GpgME::Key &key) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMECHANGEPASSWDJOB_H__
diff --git a/lang/qt/src/qgpgmecryptoconfig.cpp b/lang/qt/src/qgpgmecryptoconfig.cpp
new file mode 100644
index 0000000..fe3e54f
--- /dev/null
+++ b/lang/qt/src/qgpgmecryptoconfig.cpp
@@ -0,0 +1,948 @@
+/*
+    qgpgmecryptoconfig.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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 "qgpgmecryptoconfig.h"
+
+#include <QList>
+#include <QByteArray>
+#include <errno.h>
+#include "gpgme_backend_debug.h"
+
+#include "engineinfo.h"
+#include "global.h"
+
+#include <cassert>
+#include <QTemporaryFile>
+#include <QFile>
+#include <cstdlib>
+#include <iterator>
+#include <QStandardPaths>
+
+// 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;
+
+static const int GPGCONF_FLAG_GROUP = 1;
+static const int GPGCONF_FLAG_OPTIONAL = 2;
+static const int GPGCONF_FLAG_LIST = 4;
+static const int GPGCONF_FLAG_RUNTIME = 8;
+static const int GPGCONF_FLAG_DEFAULT = 16; // fixed default value available
+//static const int GPGCONF_FLAG_DEFAULT_DESC = 32; // runtime default value available
+//static const int GPGCONF_FLAG_NOARG_DESC = 64; // option with optional arg; special meaning if no arg set
+static const int GPGCONF_FLAG_NO_CHANGE = 128; // readonly
+// Change size of mFlags bitfield if adding new values here
+
+QString QGpgMECryptoConfig::gpgConfPath()
+{
+    const GpgME::EngineInfo info = GpgME::engineInfo(GpgME::GpgConfEngine);
+    return info.fileName() ? QFile::decodeName(info.fileName()) : QStandardPaths::findExecutable(QStringLiteral("gpgconf"));
+}
+
+QGpgMECryptoConfig::QGpgMECryptoConfig()
+    :  mParsed(false)
+{
+}
+
+QGpgMECryptoConfig::~QGpgMECryptoConfig()
+{
+    clear();
+}
+
+void QGpgMECryptoConfig::runGpgConf(bool showErrors)
+{
+    // Run gpgconf --list-components to make the list of components
+    KProcess process;
+
+    process << gpgConfPath();
+    process << QStringLiteral("--list-components");
+
+    connect(&process, &KProcess::readyReadStandardOutput, this, &QGpgMECryptoConfig::slotCollectStdOut);
+
+    // run the process:
+    int rc = 0;
+    process.setOutputChannelMode(KProcess::OnlyStdoutChannel);
+    process.start();
+    if (!process.waitForFinished()) {
+        rc = -2;
+    } else if (process.exitStatus() == QProcess::NormalExit) {
+        rc = process.exitCode();
+    } else {
+        rc = -1;
+    }
+
+    // handle errors, if any (and if requested)
+    if (showErrors && rc != 0) {
+        QString reason;
+        if (rc == -1) {
+            reason = i18n("program terminated unexpectedly");
+        } else if (rc == -2) {
+            reason = i18n("program not found or cannot be started");
+        } else {
+            reason = QString::fromLocal8Bit(strerror(rc));    // XXX errno as an exit code?
+        }
+        QString wmsg = i18n("<qt>Failed to execute gpgconf:<p>%1</p></qt>", reason);
+        qCWarning(GPGPME_BACKEND_LOG) << wmsg; // to see it from test_cryptoconfig.cpp
+        KMessageBox::error(0, wmsg);
+    }
+    mParsed = true;
+}
+
+void QGpgMECryptoConfig::slotCollectStdOut()
+{
+    assert(qobject_cast<KProcess *>(QObject::sender()));
+    KProcess *const proc = static_cast<KProcess *>(QObject::sender());
+    while (proc->canReadLine()) {
+        QString line = QString::fromUtf8(proc->readLine());
+        if (line.endsWith(QLatin1Char('\n'))) {
+            line.chop(1);
+        }
+        if (line.endsWith(QLatin1Char('\r'))) {
+            line.chop(1);
+        }
+        //qCDebug(GPGPME_BACKEND_LOG) <<"GOT LINE:" << line;
+        // Format: NAME:DESCRIPTION
+        const QStringList lst = line.split(QLatin1Char(':'));
+        if (lst.count() >= 2) {
+            const std::pair<QString, QGpgMECryptoConfigComponent *> pair(lst[0], new QGpgMECryptoConfigComponent(this, lst[0], lst[1]));
+            mComponentsNaturalOrder.push_back(pair);
+            mComponentsByName[pair.first] = pair.second;
+        } else {
+            qCWarning(GPGPME_BACKEND_LOG) << "Parse error on gpgconf --list-components output:" << line;
+        }
+    }
+}
+
+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;
+    }
+};
+}
+
+QStringList QGpgMECryptoConfig::componentList() const
+{
+    if (!mParsed) {
+        const_cast<QGpgMECryptoConfig *>(this)->runGpgConf(true);
+    }
+    QStringList result;
+    std::transform(mComponentsNaturalOrder.begin(), mComponentsNaturalOrder.end(),
+                   std::back_inserter(result), Select1St());
+    return result;
+}
+
+QGpgME::CryptoConfigComponent *QGpgMECryptoConfig::component(const QString &name) const
+{
+    if (!mParsed) {
+        const_cast<QGpgMECryptoConfig *>(this)->runGpgConf(false);
+    }
+    return mComponentsByName.value(name);
+}
+
+void QGpgMECryptoConfig::sync(bool runtime)
+{
+    Q_FOREACH (QGpgMECryptoConfigComponent *it, mComponentsByName) {
+        it->sync(runtime);
+    }
+}
+
+void QGpgMECryptoConfig::clear()
+{
+    s_duringClear = true;
+    mComponentsNaturalOrder.clear();
+    qDeleteAll(mComponentsByName);
+    mComponentsByName.clear();
+    s_duringClear = false;
+    mParsed = false; // next call to componentList/component will need to run gpgconf again
+}
+
+////
+
+QGpgMECryptoConfigComponent::QGpgMECryptoConfigComponent(QGpgMECryptoConfig *, const QString &name, const QString &description)
+    : mName(name), mDescription(description)
+{
+    runGpgConf();
+}
+
+QGpgMECryptoConfigComponent::~QGpgMECryptoConfigComponent()
+{
+    mGroupsNaturalOrder.clear();
+    qDeleteAll(mGroupsByName);
+    mGroupsByName.clear();
+}
+
+void QGpgMECryptoConfigComponent::runGpgConf()
+{
+    const QString gpgconf = QGpgMECryptoConfig::gpgConfPath();
+    if (gpgconf.isEmpty()) {
+        qCWarning(GPGPME_BACKEND_LOG) << "Can't get path to gpgconf executable...";
+        return;
+    }
+
+    // Run gpgconf --list-options <component>, and create all groups and entries for that component
+    KProcess proc;
+    proc << gpgconf;
+    proc << QStringLiteral("--list-options");
+    proc << mName;
+
+    //qCDebug(GPGPME_BACKEND_LOG) <<"Running gpgconf --list-options" << mName;
+
+    connect(&proc, &KProcess::readyReadStandardOutput, this, &QGpgMECryptoConfigComponent::slotCollectStdOut);
+    mCurrentGroup = 0;
+
+    // run the process:
+    int rc = 0;
+    proc.setOutputChannelMode(KProcess::OnlyStdoutChannel);
+    proc.start();
+    if (!proc.waitForFinished()) {
+        rc = -2;
+    } else if (proc.exitStatus() == QProcess::NormalExit) {
+        rc = proc.exitCode();
+    } else {
+        rc = -1;
+    }
+
+    if (rc != 0) { // can happen when using the wrong version of gpg...
+        qCWarning(GPGPME_BACKEND_LOG) << "Running 'gpgconf --list-options" << mName << "' failed." << strerror(rc) << ", but try that command to see the real output";
+    } else {
+        if (mCurrentGroup && !mCurrentGroup->mEntriesNaturalOrder.empty()) {   // only add non-empty groups
+            mGroupsByName.insert(mCurrentGroupName, mCurrentGroup);
+            mGroupsNaturalOrder.push_back(std::make_pair(mCurrentGroupName, mCurrentGroup));
+        }
+    }
+}
+
+void QGpgMECryptoConfigComponent::slotCollectStdOut()
+{
+    assert(qobject_cast<KProcess *>(QObject::sender()));
+    KProcess *const proc = static_cast<KProcess *>(QObject::sender());
+    while (proc->canReadLine()) {
+        QString line = QString::fromUtf8(proc->readLine());
+        if (line.endsWith(QLatin1Char('\n'))) {
+            line.chop(1);
+        }
+        if (line.endsWith(QLatin1Char('\r'))) {
+            line.chop(1);
+        }
+        //qCDebug(GPGPME_BACKEND_LOG) <<"GOT LINE:" << line;
+        // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
+        const QStringList lst = line.split(QLatin1Char(':'));
+        if (lst.count() >= 10) {
+            const int flags = lst[1].toInt();
+            const int level = lst[2].toInt();
+            if (level > 2) { // invisible or internal -> skip it;
+                continue;
+            }
+            if (flags & GPGCONF_FLAG_GROUP) {
+                if (mCurrentGroup && !mCurrentGroup->mEntriesNaturalOrder.empty()) {   // only add non-empty groups
+                    mGroupsByName.insert(mCurrentGroupName, mCurrentGroup);
+                    mGroupsNaturalOrder.push_back(std::make_pair(mCurrentGroupName, mCurrentGroup));
+                }
+                //else
+                //  qCDebug(GPGPME_BACKEND_LOG) <<"Discarding empty group" << mCurrentGroupName;
+                mCurrentGroup = new QGpgMECryptoConfigGroup(this, lst[0], lst[3], level);
+                mCurrentGroupName = lst[0];
+            } else {
+                // normal entry
+                if (!mCurrentGroup) {    // first toplevel entry -> create toplevel group
+                    mCurrentGroup = new QGpgMECryptoConfigGroup(this, QStringLiteral("<nogroup>"), QString(), 0);
+                    mCurrentGroupName = QStringLiteral("<nogroup>");
+                }
+                const QString &name = lst[0];
+                QGpgMECryptoConfigEntry *value = new QGpgMECryptoConfigEntry(mCurrentGroup, lst);
+                mCurrentGroup->mEntriesByName.insert(name, value);
+                mCurrentGroup->mEntriesNaturalOrder.push_back(std::make_pair(name, value));
+            }
+        } else {
+            // This happens on lines like
+            // dirmngr[31465]: error opening `/home/dfaure/.gnupg/dirmngr_ldapservers.conf': No such file or directory
+            // so let's not bother the user with it.
+            //qCWarning(GPGPME_BACKEND_LOG) <<"Parse error on gpgconf --list-options output:" << line;
+        }
+    }
+}
+
+QStringList QGpgMECryptoConfigComponent::groupList() const
+{
+    QStringList result;
+    std::transform(mGroupsNaturalOrder.begin(), mGroupsNaturalOrder.end(),
+                   std::back_inserter(result), Select1St());
+    return result;
+}
+
+QGpgME::CryptoConfigGroup *QGpgMECryptoConfigComponent::group(const QString &name) const
+{
+    return mGroupsByName.value(name);
+}
+
+void QGpgMECryptoConfigComponent::sync(bool runtime)
+{
+    QTemporaryFile tmpFile;
+    tmpFile.open();
+
+    QList<QGpgMECryptoConfigEntry *> dirtyEntries;
+
+    // Collect all dirty entries
+    const QList<QString> keylist = mGroupsByName.uniqueKeys();
+    Q_FOREACH (const QString &key, keylist) {
+        const QHash<QString, QGpgMECryptoConfigEntry *> entry = mGroupsByName[key]->mEntriesByName;
+        const QList<QString> keylistentry = entry.uniqueKeys();
+        Q_FOREACH (const QString &keyentry, keylistentry) {
+            if (entry[keyentry]->isDirty()) {
+                // OK, we can set it.currentKey() to it.current()->outputString()
+                QString line = keyentry;
+                if (entry[keyentry]->isSet()) {   // set option
+                    line += QLatin1String(":0:");
+                    line += entry[keyentry]->outputString();
+                } else {                       // unset option
+                    line += QLatin1String(":16:");
+                }
+#ifdef Q_OS_WIN
+                line += QLatin1Char('\r');
+#endif
+                line += QLatin1Char('\n');
+                const QByteArray line8bit = line.toUtf8(); // encode with utf8, and K3ProcIO uses utf8 when reading.
+                tmpFile.write(line8bit);
+                dirtyEntries.append(entry[keyentry]);
+
+            }
+        }
+    }
+
+    tmpFile.flush();
+    if (dirtyEntries.isEmpty()) {
+        return;
+    }
+
+    // Call gpgconf --change-options <component>
+    const QString gpgconf = QGpgMECryptoConfig::gpgConfPath();
+    QString commandLine = gpgconf.isEmpty()
+                          ? QStringLiteral("gpgconf")
+                          : KShell::quoteArg(gpgconf);
+    if (runtime) {
+        commandLine += QLatin1String(" --runtime");
+    }
+    commandLine += QLatin1String(" --change-options ");
+    commandLine += KShell::quoteArg(mName);
+    commandLine += QLatin1String(" < ");
+    commandLine += KShell::quoteArg(tmpFile.fileName());
+
+    //qCDebug(GPGPME_BACKEND_LOG) << commandLine;
+    //system( QCString( "cat " ) + tmpFile.name().toLatin1() ); // DEBUG
+
+    KProcess proc;
+    proc.setShellCommand(commandLine);
+
+    // run the process:
+    int rc = proc.execute();
+
+    if (rc == -2) {
+        QString wmsg = i18n("Could not start gpgconf.\nCheck that gpgconf is in the PATH and that it can be started.");
+        qCWarning(GPGPME_BACKEND_LOG) << wmsg;
+        KMessageBox::error(0, wmsg);
+    } else if (rc != 0) { // Happens due to bugs in gpgconf (e.g. issues 104/115)
+        QString wmsg = i18n("Error from gpgconf while saving configuration: %1", QString::fromLocal8Bit(strerror(rc)));
+        qCWarning(GPGPME_BACKEND_LOG) << ":" << strerror(rc);
+        KMessageBox::error(0, wmsg);
+    } else {
+        QList<QGpgMECryptoConfigEntry *>::const_iterator it = dirtyEntries.constBegin();
+        for (; it != dirtyEntries.constEnd(); ++it) {
+            (*it)->setDirty(false);
+        }
+    }
+}
+
+////
+
+QGpgMECryptoConfigGroup::QGpgMECryptoConfigGroup(QGpgMECryptoConfigComponent *comp, const QString &name, const QString &description, int level)
+    :
+    mComponent(comp),
+    mName(name),
+    mDescription(description),
+    mLevel(static_cast<QGpgME::CryptoConfigEntry::Level>(level))
+{
+}
+
+QGpgMECryptoConfigGroup::~QGpgMECryptoConfigGroup()
+{
+    mEntriesNaturalOrder.clear();
+    qDeleteAll(mEntriesByName);
+    mEntriesByName.clear();
+}
+
+QStringList QGpgMECryptoConfigGroup::entryList() const
+{
+    QStringList result;
+    std::transform(mEntriesNaturalOrder.begin(), mEntriesNaturalOrder.end(),
+                   std::back_inserter(result), Select1St());
+    return result;
+}
+
+QGpgME::CryptoConfigEntry *QGpgMECryptoConfigGroup::entry(const QString &name) const
+{
+    return mEntriesByName.value(name);
+}
+
+////
+
+static QString gpgconf_unescape(const QString &str, bool handleComma = true)
+{
+    /* See gpgconf_escape */
+    QString dec(str);
+    dec.replace(QStringLiteral("%25"), QStringLiteral("%"));
+    dec.replace(QStringLiteral("%3a"), QStringLiteral(":"));
+    if (handleComma) {
+        dec.replace(QStringLiteral("%2c"), QStringLiteral(","));
+    }
+    return dec;
+}
+
+static QString gpgconf_escape(const QString &str, bool handleComma = true)
+{
+    /* Gpgconf does not really percent encode. It just
+     * encodes , % and : characters. It expects all other
+     * chars to be UTF-8 encoded.
+     * Except in the Base-DN part where a , may not be percent
+     * escaped.
+     */
+    QString esc(str);
+    esc.replace(QLatin1Char('%'), QStringLiteral("%25"));
+    esc.replace(QLatin1Char(':'), QStringLiteral("%3a"));
+    if (handleComma) {
+        esc.replace(QLatin1Char(','), QStringLiteral("%2c"));
+    }
+    return esc;
+}
+
+static QString urlpart_escape(const QString &str)
+{
+    /* We need to double escape here, as a username or password
+     * or an LDAP Base-DN may contain : or , and in that
+     * case we would break gpgconf's format if we only escaped
+     * the : once. As an escaped : is used internaly to split
+     * the parts of an url. */
+
+    return gpgconf_escape(gpgconf_escape(str, false), false);
+}
+
+static QString urlpart_unescape(const QString &str)
+{
+    /* See urlpart_escape */
+    return gpgconf_unescape(gpgconf_unescape(str, false), false);
+}
+
+// gpgconf arg type number -> CryptoConfigEntry 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;
+    }
+}
+
+QGpgMECryptoConfigEntry::QGpgMECryptoConfigEntry(QGpgMECryptoConfigGroup *group, const QStringList &parsedLine)
+    : mGroup(group)
+{
+    // Format: NAME:FLAGS:LEVEL:DESCRIPTION:TYPE:ALT-TYPE:ARGNAME:DEFAULT:ARGDEF:VALUE
+    assert(parsedLine.count() >= 10);   // called checked for it already
+    QStringList::const_iterator it = parsedLine.constBegin();
+    mName = *it++;
+    mFlags = (*it++).toInt();
+    mLevel = (*it++).toInt();
+    mDescription = *it++;
+    bool ok;
+    // we keep the real (int) arg type, since it influences the parsing (e.g. for ldap urls)
+    mRealArgType = (*it++).toInt();
+    mArgType = knownArgType(mRealArgType, ok);
+    if (!ok && !(*it).isEmpty()) {
+        // use ALT-TYPE
+        mRealArgType = (*it).toInt();
+        mArgType = knownArgType(mRealArgType, ok);
+    }
+    if (!ok) {
+        qCWarning(GPGPME_BACKEND_LOG) << "Unsupported datatype:" << parsedLine[4] << " :" << *it << " for" << parsedLine[0];
+    }
+    ++it; // done with alt-type
+    ++it; // skip argname (not useful in GUIs)
+
+    mSet = false;
+    QString value;
+    if (mFlags & GPGCONF_FLAG_DEFAULT) {
+        value = *it; // get default value
+        mDefaultValue = stringToValue(value, true);
+    }
+    ++it; // done with DEFAULT
+    ++it; // ### skip ARGDEF for now. It's only for options with an "optional arg"
+    //qCDebug(GPGPME_BACKEND_LOG) <<"Entry" << parsedLine[0] <<" val=" << *it;
+
+    if (!(*it).isEmpty()) {    // a real value was set
+        mSet = true;
+        value = *it;
+        mValue = stringToValue(value, true);
+    } else {
+        mValue = mDefaultValue;
+    }
+
+    mDirty = false;
+}
+
+QVariant QGpgMECryptoConfigEntry::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(QLatin1Char(','), 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] != QLatin1Char('"')) { // 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] != QLatin1Char('"')) { // see README.gpgconf
+                    qCWarning(GPGPME_BACKEND_LOG) << "String value should start with '\"' :" << val;
+                }
+                val = val.mid(1);
+            }
+        }
+        return QVariant(unescape ? gpgconf_unescape(val) : val);
+    }
+}
+
+QGpgMECryptoConfigEntry::~QGpgMECryptoConfigEntry()
+{
+#ifndef NDEBUG
+    if (!s_duringClear && mDirty)
+        qCWarning(GPGPME_BACKEND_LOG) << "Deleting a QGpgMECryptoConfigEntry that was modified (" << mDescription << ")"
+                                      << "You forgot to call sync() (to commit) or clear() (to discard)";
+#endif
+}
+
+bool QGpgMECryptoConfigEntry::isOptional() const
+{
+    return mFlags & GPGCONF_FLAG_OPTIONAL;
+}
+
+bool QGpgMECryptoConfigEntry::isReadOnly() const
+{
+    return mFlags & GPGCONF_FLAG_NO_CHANGE;
+}
+
+bool QGpgMECryptoConfigEntry::isList() const
+{
+    return mFlags & GPGCONF_FLAG_LIST;
+}
+
+bool QGpgMECryptoConfigEntry::isRuntime() const
+{
+    return mFlags & GPGCONF_FLAG_RUNTIME;
+}
+
+bool QGpgMECryptoConfigEntry::isSet() const
+{
+    return mSet;
+}
+
+bool QGpgMECryptoConfigEntry::boolValue() const
+{
+    Q_ASSERT(mArgType == ArgType_None);
+    Q_ASSERT(!isList());
+    return mValue.toBool();
+}
+
+QString QGpgMECryptoConfigEntry::stringValue() const
+{
+    return toString(false);
+}
+
+int QGpgMECryptoConfigEntry::intValue() const
+{
+    Q_ASSERT(mArgType == ArgType_Int);
+    Q_ASSERT(!isList());
+    return mValue.toInt();
+}
+
+unsigned int QGpgMECryptoConfigEntry::uintValue() const
+{
+    Q_ASSERT(mArgType == ArgType_UInt);
+    Q_ASSERT(!isList());
+    return mValue.toUInt();
+}
+
+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(gpgconf_unescape(*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_unescape(*it++);
+            if (!userName.isEmpty()) {
+                url.setUserName(userName);
+            }
+            const QString passWord = urlpart_unescape(*it++);
+            if (!passWord.isEmpty()) {
+                url.setPassword(passWord);
+            }
+            url.setQuery(urlpart_unescape(*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 gpgconf_escape(url.host()) + QLatin1Char(':') +
+               (url.port() != -1 ? QString::number(url.port()) : QString()) + QLatin1Char(':') +     // -1 is used for default ports, omit
+               urlpart_escape(url.userName()) + QLatin1Char(':') +
+               urlpart_escape(url.password()) + QLatin1Char(':') +
+               urlpart_escape(url.query());
+    }
+    return url.path();
+}
+
+QUrl QGpgMECryptoConfigEntry::urlValue() const
+{
+    Q_ASSERT(mArgType == ArgType_Path || mArgType == ArgType_LDAPURL);
+    Q_ASSERT(!isList());
+    QString str = mValue.toString();
+    if (mArgType == ArgType_Path) {
+        QUrl url = QUrl::fromUserInput(str, QString(), QUrl::AssumeLocalFile);
+        return url;
+    }
+    return parseURL(mRealArgType, str);
+}
+
+unsigned int QGpgMECryptoConfigEntry::numberOfTimesSet() const
+{
+    Q_ASSERT(mArgType == ArgType_None);
+    Q_ASSERT(isList());
+    return mValue.toUInt();
+}
+
+std::vector<int> QGpgMECryptoConfigEntry::intValueList() const
+{
+    Q_ASSERT(mArgType == ArgType_Int);
+    Q_ASSERT(isList());
+    std::vector<int> ret;
+    QList<QVariant> lst = mValue.toList();
+    ret.reserve(lst.size());
+    for (QList<QVariant>::const_iterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
+        ret.push_back((*it).toInt());
+    }
+    return ret;
+}
+
+std::vector<unsigned int> QGpgMECryptoConfigEntry::uintValueList() const
+{
+    Q_ASSERT(mArgType == ArgType_UInt);
+    Q_ASSERT(isList());
+    std::vector<unsigned int> ret;
+    QList<QVariant> lst = mValue.toList();
+    ret.reserve(lst.size());
+    for (QList<QVariant>::const_iterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
+        ret.push_back((*it).toUInt());
+    }
+    return ret;
+}
+
+QList<QUrl> QGpgMECryptoConfigEntry::urlValueList() const
+{
+    Q_ASSERT(mArgType == ArgType_Path || mArgType == ArgType_LDAPURL);
+    Q_ASSERT(isList());
+    QStringList lst = mValue.toStringList();
+
+    QList<QUrl> ret;
+    for (QStringList::const_iterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
+        if (mArgType == ArgType_Path) {
+            QUrl url = QUrl::fromUserInput(*it, QString(), QUrl::AssumeLocalFile);
+        } else {
+            ret << parseURL(mRealArgType, *it);
+        }
+    }
+    return ret;
+}
+
+void QGpgMECryptoConfigEntry::resetToDefault()
+{
+    mSet = false;
+    mDirty = true;
+    if (mFlags & GPGCONF_FLAG_DEFAULT) {
+        mValue = mDefaultValue;
+    } else if (mArgType == ArgType_None) {
+        if (isList()) {
+            mValue = 0U;
+        } else {
+            mValue = false;
+        }
+    }
+}
+
+void QGpgMECryptoConfigEntry::setBoolValue(bool b)
+{
+    Q_ASSERT(mArgType == ArgType_None);
+    Q_ASSERT(!isList());
+    // A "no arg" option is either set or not set.
+    // Being set means mSet==true + mValue==true, being unset means resetToDefault(), i.e. both false
+    mValue = b;
+    mSet = b;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setStringValue(const QString &str)
+{
+    mValue = stringToValue(str, false);
+    // 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()) {
+        mSet = false;
+    } else {
+        mSet = true;
+    }
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setIntValue(int i)
+{
+    Q_ASSERT(mArgType == ArgType_Int);
+    Q_ASSERT(!isList());
+    mValue = i;
+    mSet = true;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setUIntValue(unsigned int i)
+{
+    mValue = i;
+    mSet = true;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setURLValue(const QUrl &url)
+{
+    QString str = splitURL(mRealArgType, url);
+    if (str.isEmpty() && !isOptional()) {
+        mSet = false;
+    } else {
+        mSet = true;
+    }
+    mValue = str;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setNumberOfTimesSet(unsigned int i)
+{
+    Q_ASSERT(mArgType == ArgType_None);
+    Q_ASSERT(isList());
+    mValue = i;
+    mSet = i > 0;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setIntValueList(const std::vector<int> &lst)
+{
+    QList<QVariant> ret;
+    for (std::vector<int>::const_iterator it = lst.begin(); it != lst.end(); ++it) {
+        ret << QVariant(*it);
+    }
+    mValue = ret;
+    if (ret.isEmpty() && !isOptional()) {
+        mSet = false;
+    } else {
+        mSet = true;
+    }
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setUIntValueList(const std::vector<unsigned int> &lst)
+{
+    QList<QVariant> ret;
+    for (std::vector<unsigned int>::const_iterator it = lst.begin(); it != lst.end(); ++it) {
+        ret << QVariant(*it);
+    }
+    if (ret.isEmpty() && !isOptional()) {
+        mSet = false;
+    } else {
+        mSet = true;
+    }
+    mValue = ret;
+    mDirty = true;
+}
+
+void QGpgMECryptoConfigEntry::setURLValueList(const QList<QUrl> &urls)
+{
+    QStringList lst;
+    for (QList<QUrl>::const_iterator it = urls.constBegin(); it != urls.constEnd(); ++it) {
+        lst << splitURL(mRealArgType, *it);
+    }
+    mValue = lst;
+    if (lst.isEmpty() && !isOptional()) {
+        mSet = false;
+    } else {
+        mSet = true;
+    }
+    mDirty = true;
+}
+
+QString QGpgMECryptoConfigEntry::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(QLatin1String("\""));
+                    }
+                }
+            }
+            const QString res = lst.join(QStringLiteral(","));
+            //qCDebug(GPGPME_BACKEND_LOG) <<"toString:" << res;
+            return res;
+        } else { // normal string
+            QString res = mValue.toString();
+            if (escape) {
+                res = gpgconf_escape(res).prepend(QLatin1String("\""));
+            }
+            return res;
+        }
+    }
+    if (!isList()) { // non-list non-string
+        if (mArgType == ArgType_None) {
+            return mValue.toBool() ? QStringLiteral("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(QStringLiteral(","));
+}
+
+QString QGpgMECryptoConfigEntry::outputString() const
+{
+    Q_ASSERT(mSet);
+    return toString(true);
+}
+
+bool QGpgMECryptoConfigEntry::isStringType() const
+{
+    return (mArgType == QGpgME::CryptoConfigEntry::ArgType_String
+            || mArgType == QGpgME::CryptoConfigEntry::ArgType_Path
+            || mArgType == QGpgME::CryptoConfigEntry::ArgType_LDAPURL);
+}
+
+void QGpgMECryptoConfigEntry::setDirty(bool b)
+{
+    mDirty = b;
+}
diff --git a/lang/qt/src/qgpgmecryptoconfig.h b/lang/qt/src/qgpgmecryptoconfig.h
new file mode 100644
index 0000000..b4af1e6
--- /dev/null
+++ b/lang/qt/src/qgpgmecryptoconfig.h
@@ -0,0 +1,245 @@
+/*
+    qgpgmecryptoconfig.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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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_QGPGMECRYPTOCONFIG_H
+#define QGPGME_QGPGMECRYPTOCONFIG_H
+
+#include "qgpgme_export.h"
+#include "cryptoconfig.h"
+
+#include <QHash>
+#include <QStringList>
+#include <QObject>
+#include <QVariant>
+#include <QPointer>
+
+#include <vector>
+#include <utility>
+
+class QGpgMECryptoConfigComponent;
+class QGpgMECryptoConfigEntry;
+/**
+ * CryptoConfig implementation around the gpgconf command-line tool
+ * For method docu, see kleo/cryptoconfig.h
+ */
+class QGPGME_EXPORT QGpgMECryptoConfig : public QObject, public QGpgME::CryptoConfig
+{
+
+    Q_OBJECT
+public:
+
+    static QString gpgConfPath();
+    /**
+     * Constructor
+     */
+    QGpgMECryptoConfig();
+    virtual ~QGpgMECryptoConfig();
+
+    QStringList componentList() const Q_DECL_OVERRIDE;
+
+    QGpgME::CryptoConfigComponent *component(const QString &name) const Q_DECL_OVERRIDE;
+
+    void clear() Q_DECL_OVERRIDE;
+    void sync(bool runtime) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    void slotCollectStdOut();
+private:
+    /// @param showErrors if true, a messagebox will be shown if e.g. gpgconf wasn't found
+    void runGpgConf(bool showErrors);
+
+private:
+    std::vector<std::pair<QString, QGpgMECryptoConfigComponent *> > mComponentsNaturalOrder;
+    QHash<QString, QGpgMECryptoConfigComponent *> mComponentsByName;
+    bool mParsed;
+};
+
+class QGpgMECryptoConfigGroup;
+
+/// For docu, see kleo/cryptoconfig.h
+class QGpgMECryptoConfigComponent : public QObject, public QGpgME::CryptoConfigComponent
+{
+
+    Q_OBJECT
+public:
+    QGpgMECryptoConfigComponent(QGpgMECryptoConfig *, const QString &name, const QString &description);
+    ~QGpgMECryptoConfigComponent();
+
+    QString name() const Q_DECL_OVERRIDE
+    {
+        return mName;
+    }
+    QString iconName() const Q_DECL_OVERRIDE
+    {
+        return mName;
+    }
+    QString description() const Q_DECL_OVERRIDE
+    {
+        return mDescription;
+    }
+    QStringList groupList() const Q_DECL_OVERRIDE;
+    QGpgME::CryptoConfigGroup *group(const QString &name) const Q_DECL_OVERRIDE;
+
+    void sync(bool runtime);
+
+private Q_SLOTS:
+    void slotCollectStdOut();
+private:
+    void runGpgConf();
+
+private:
+    std::vector< std::pair<QString, QGpgMECryptoConfigGroup *> > mGroupsNaturalOrder;
+    QHash<QString, QGpgMECryptoConfigGroup *> mGroupsByName;
+    QString mName;
+    QString mDescription;
+    QGpgMECryptoConfigGroup *mCurrentGroup; // during parsing
+    QString mCurrentGroupName; // during parsing
+};
+
+class QGpgMECryptoConfigGroup : public QGpgME::CryptoConfigGroup
+{
+
+public:
+    QGpgMECryptoConfigGroup(QGpgMECryptoConfigComponent *comp, const QString &name, const QString &description, int level);
+    ~QGpgMECryptoConfigGroup();
+
+    QString name() const Q_DECL_OVERRIDE
+    {
+        return mName;
+    }
+    QString iconName() const Q_DECL_OVERRIDE
+    {
+        return QString();
+    }
+    QString description() const Q_DECL_OVERRIDE
+    {
+        return mDescription;
+    }
+    QString path() const Q_DECL_OVERRIDE
+    {
+        return mComponent->name() + QLatin1Char('/') + mName;
+    }
+    QGpgME::CryptoConfigEntry::Level level() const Q_DECL_OVERRIDE
+    {
+        return mLevel;
+    }
+    QStringList entryList() const Q_DECL_OVERRIDE;
+    QGpgME::CryptoConfigEntry *entry(const QString &name) const Q_DECL_OVERRIDE;
+
+private:
+    friend class QGpgMECryptoConfigComponent; // it adds the entries
+    QPointer<QGpgMECryptoConfigComponent> mComponent;
+    std::vector< std::pair<QString, QGpgMECryptoConfigEntry *> > mEntriesNaturalOrder;
+    QHash<QString, QGpgMECryptoConfigEntry *> mEntriesByName;
+    QString mName;
+    QString mDescription;
+    QGpgME::CryptoConfigEntry::Level mLevel;
+};
+
+class QGpgMECryptoConfigEntry : public QGpgME::CryptoConfigEntry
+{
+public:
+    QGpgMECryptoConfigEntry(QGpgMECryptoConfigGroup *group, const QStringList &parsedLine);
+    ~QGpgMECryptoConfigEntry();
+
+    QString name() const Q_DECL_OVERRIDE
+    {
+        return mName;
+    }
+    QString description() const Q_DECL_OVERRIDE
+    {
+        return mDescription;
+    }
+    QString path() const Q_DECL_OVERRIDE
+    {
+        return mGroup->path() + QLatin1Char('/') + mName;
+    }
+    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
+    {
+        return static_cast<Level>(mLevel);
+    }
+    ArgType argType() const Q_DECL_OVERRIDE
+    {
+        return static_cast<ArgType>(mArgType);
+    }
+    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
+    {
+        return mDirty;
+    }
+
+    void setDirty(bool b);
+    QString outputString() const;
+
+protected:
+    bool isStringType() const;
+    QVariant stringToValue(const QString &value, bool unescape) const;
+    QString toString(bool escape) const;
+private:
+    QGpgMECryptoConfigGroup *mGroup;
+    QString mName;
+    QString mDescription;
+    QVariant mDefaultValue;
+    QVariant mValue;
+    uint mFlags : 8; // bitfield with 8 bits
+    uint mLevel : 3; // max is 4 (2, in fact) -> 3 bits
+    uint mRealArgType : 6; // max is 33 -> 6 bits
+    uint mArgType : 3; // max is 6 (ArgType enum) -> 3 bits;
+    uint mDirty : 1;
+    uint mSet : 1;
+};
+
+#endif /* QGPGME_QGPGMECRYPTOCONFIG_H */
diff --git a/lang/qt/src/qgpgmedecryptjob.cpp b/lang/qt/src/qgpgmedecryptjob.cpp
new file mode 100644
index 0000000..f084e2a
--- /dev/null
+++ b/lang/qt/src/qgpgmedecryptjob.cpp
@@ -0,0 +1,127 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+QGpgMEDecryptJob::QGpgMEDecryptJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEDecryptJob::~QGpgMEDecryptJob() {}
+
+static QGpgMEDecryptJob::result_type decrypt(Context *ctx, QThread *thread, const weak_ptr<QIODevice> &cipherText_, const weak_ptr<QIODevice> &plainText_)
+{
+
+    const shared_ptr<QIODevice> cipherText = cipherText_.lock();
+    const 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 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 make_tuple(res, QByteArray(), log, ae);
+    }
+
+}
+
+static QGpgMEDecryptJob::result_type decrypt_qba(Context *ctx, const QByteArray &cipherText)
+{
+    const 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, shared_ptr<QIODevice>());
+}
+
+Error QGpgMEDecryptJob::start(const QByteArray &cipherText)
+{
+    run(bind(&decrypt_qba, _1, cipherText));
+    return Error();
+}
+
+void QGpgMEDecryptJob::start(const shared_ptr<QIODevice> &cipherText, const shared_ptr<QIODevice> &plainText)
+{
+    run(bind(&decrypt, _1, _2, _3, _4), cipherText, plainText);
+}
+
+GpgME::DecryptionResult QGpgME::QGpgMEDecryptJob::exec(const QByteArray &cipherText,
+        QByteArray &plainText)
+{
+    const result_type r = decrypt_qba(context(), cipherText);
+    plainText = get<1>(r);
+    resultHook(r);
+    return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgMEDecryptJob::resultHook(const result_type &tuple)
+{
+    mResult = get<0>(tuple);
+}
diff --git a/lang/qt/src/qgpgmedecryptjob.h b/lang/qt/src/qgpgmedecryptjob.h
new file mode 100644
index 0000000..55eb26e
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from DecryptJob */
+    GpgME::Error start(const QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+    /*! \reimp from DecryptJob */
+    void start(const boost::shared_ptr<QIODevice> &cipherText, const boost::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+    /*! \reimp from DecryptJob */
+    GpgME::DecryptionResult exec(const QByteArray &cipherText,
+                                 QByteArray &plainText) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..635511e
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+QGpgMEDecryptVerifyJob::QGpgMEDecryptVerifyJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEDecryptVerifyJob::~QGpgMEDecryptVerifyJob() {}
+
+static QGpgMEDecryptVerifyJob::result_type decrypt_verify(Context *ctx, QThread *thread, const weak_ptr<QIODevice> &cipherText_, const weak_ptr<QIODevice> &plainText_)
+{
+
+    qCDebug(GPGPME_BACKEND_LOG);
+
+    const shared_ptr<QIODevice> cipherText = cipherText_.lock();
+    const 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 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 make_tuple(res.first, res.second, QByteArray(), log, ae);
+    }
+
+}
+
+static QGpgMEDecryptVerifyJob::result_type decrypt_verify_qba(Context *ctx, const QByteArray &cipherText)
+{
+    const 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, shared_ptr<QIODevice>());
+}
+
+Error QGpgMEDecryptVerifyJob::start(const QByteArray &cipherText)
+{
+    run(bind(&decrypt_verify_qba, _1, cipherText));
+    return Error();
+}
+
+void QGpgMEDecryptVerifyJob::start(const shared_ptr<QIODevice> &cipherText, const shared_ptr<QIODevice> &plainText)
+{
+    run(bind(&decrypt_verify, _1, _2, _3, _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 = get<2>(r);
+    resultHook(r);
+    return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgMEDecryptVerifyJob::resultHook(const result_type &tuple)
+{
+    mResult = std::make_pair(get<0>(tuple), get<1>(tuple));
+}
diff --git a/lang/qt/src/qgpgmedecryptverifyjob.h b/lang/qt/src/qgpgmedecryptverifyjob.h
new file mode 100644
index 0000000..37b8e1e
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from DecryptVerifyJob */
+    GpgME::Error start(const QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+    /*! \reimp from DecryptVerifyJob */
+    void start(const boost::shared_ptr<QIODevice> &cipherText, const boost::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+    /*! \reimp from DecryptVerifyJob */
+    std::pair<GpgME::DecryptionResult, GpgME::VerificationResult>
+    exec(const QByteArray &cipherText, QByteArray &plainText) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..c5f5253
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 make_tuple(err, log, ae);
+}
+
+Error QGpgMEDeleteJob::start(const Key &key, bool allowSecretKeyDeletion)
+{
+    run(bind(&delete_key, _1, key, allowSecretKeyDeletion));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmedeletejob.h b/lang/qt/src/qgpgmedeletejob.h
new file mode 100644
index 0000000..dea2d85
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp 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..3baa629
--- /dev/null
+++ b/lang/qt/src/qgpgmedownloadjob.cpp
@@ -0,0 +1,102 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+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 make_tuple(err, dp.data(), log, ae);
+}
+
+static QGpgMEDownloadJob::result_type download(Context *ctx, QThread *thread, const QByteArray &fpr, const weak_ptr<QIODevice> &keyData_)
+{
+    const 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 make_tuple(err, QByteArray(), log, ae);
+}
+
+Error QGpgMEDownloadJob::start(const QStringList &pats)
+{
+    run(bind(&download_qsl, _1, pats));
+    return Error();
+}
+
+Error QGpgMEDownloadJob::start(const QByteArray &fpr, const boost::shared_ptr<QIODevice> &keyData)
+{
+    run(bind(&download, _1, _2, fpr, _3), keyData);
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmedownloadjob.h b/lang/qt/src/qgpgmedownloadjob.h
new file mode 100644
index 0000000..58fe7f9
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from DownloadJob */
+    GpgME::Error start(const QStringList &fingerprints) Q_DECL_OVERRIDE;
+
+    /*! \reimp from DownloadJob */
+    GpgME::Error start(const QByteArray &fingerprint, const boost::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..4618e4a
--- /dev/null
+++ b/lang/qt/src/qgpgmeencryptjob.cpp
@@ -0,0 +1,161 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+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 weak_ptr<QIODevice> &plainText_,
+        const weak_ptr<QIODevice> &cipherText_,
+        bool alwaysTrust,
+        bool outputIsBsse64Encoded)
+{
+
+    const shared_ptr<QIODevice> plainText = plainText_.lock();
+    const 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);
+
+    const Context::EncryptionFlags eflags =
+        alwaysTrust ? Context::AlwaysTrust : Context::None;
+
+    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 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 make_tuple(res, QByteArray(), log, ae);
+    }
+
+}
+
+static QGpgMEEncryptJob::result_type encrypt_qba(Context *ctx, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, bool outputIsBsse64Encoded)
+{
+    const 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, shared_ptr<QIODevice>(), alwaysTrust, outputIsBsse64Encoded);
+}
+
+Error QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
+{
+    run(boost::bind(&encrypt_qba, _1, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded));
+    return Error();
+}
+
+void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const shared_ptr<QIODevice> &plainText, const shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+{
+    run(boost::bind(&encrypt,
+                    _1, _2,
+                    recipients,
+                    _3, _4,
+                    alwaysTrust,
+                    mOutputIsBase64Encoded),
+        plainText, cipherText);
+}
+
+EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+    const result_type r = encrypt_qba(context(), recipients, plainText, alwaysTrust, mOutputIsBase64Encoded);
+    cipherText = get<1>(r);
+    resultHook(r);
+    return mResult;
+}
+
+void QGpgMEEncryptJob::resultHook(const result_type &tuple)
+{
+    mResult = 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
diff --git a/lang/qt/src/qgpgmeencryptjob.h b/lang/qt/src/qgpgmeencryptjob.h
new file mode 100644
index 0000000..ff9b7a9
--- /dev/null
+++ b/lang/qt/src/qgpgmeencryptjob.h
@@ -0,0 +1,102 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from EncryptJob */
+    GpgME::Error start(const std::vector<GpgME::Key> &recipients,
+                       const QByteArray &plainText, bool alwaysTrust) Q_DECL_OVERRIDE;
+
+    /*! \reimp from EncryptJob */
+    void start(const std::vector<GpgME::Key> &recipients,
+               const boost::shared_ptr<QIODevice> &plainText,
+               const boost::shared_ptr<QIODevice> &cipherText,
+               bool alwaysTrust) Q_DECL_OVERRIDE;
+
+    /*! \reimp from EncryptJob */
+    GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+                                 const QByteArray &plainText, bool alwaysTrust,
+                                 QByteArray &cipherText) Q_DECL_OVERRIDE;
+
+    /*! \reimp from Job */
+    void showErrorDialog(QWidget *parent, const QString &caption) const Q_DECL_OVERRIDE;
+
+    /*! \reimp from EncryptJob */
+    void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..12bbfd2
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 make_tuple(err, dp.data(), log, ae);
+}
+
+Error QGpgMEExportJob::start(const QStringList &patterns)
+{
+    run(bind(&export_qba, _1, patterns));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmeexportjob.h b/lang/qt/src/qgpgmeexportjob.h
new file mode 100644
index 0000000..4606b3e
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp 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..846ebee
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 make_tuple(res, log, ae);
+}
+
+Error QGpgMEImportFromKeyserverJob::start(const std::vector<Key> &keys)
+{
+    run(boost::bind(&importfromkeyserver, _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 = get<0>(tuple);
+}
diff --git a/lang/qt/src/qgpgmeimportfromkeyserverjob.h b/lang/qt/src/qgpgmeimportfromkeyserverjob.h
new file mode 100644
index 0000000..508aa09
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from ImportFromKeyserverJob */
+    GpgME::Error start(const std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+    /*! \reimp from ImportFromKeyserverJob */
+    GpgME::ImportResult exec(const std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..973a0bf
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 make_tuple(res, log, ae);
+}
+
+Error QGpgMEImportJob::start(const QByteArray &certData)
+{
+    run(bind(&import_qba, _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 = get<0>(tuple);
+}
diff --git a/lang/qt/src/qgpgmeimportjob.h b/lang/qt/src/qgpgmeimportjob.h
new file mode 100644
index 0000000..e023c69
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from ImportJob */
+    GpgME::Error start(const QByteArray &keyData) Q_DECL_OVERRIDE;
+
+    /*! \reimp from ImportJob */
+    GpgME::ImportResult exec(const QByteArray &keyData) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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/qgpgmekeygenerationjob.cpp b/lang/qt/src/qgpgmekeygenerationjob.cpp
new file mode 100644
index 0000000..56323c9
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 make_tuple(res, dp.data(), log, ae);
+}
+
+Error QGpgMEKeyGenerationJob::start(const QString &parameters)
+{
+    run(bind(&generate_key, _1, parameters));
+    return Error();
+}
diff --git a/lang/qt/src/qgpgmekeygenerationjob.h b/lang/qt/src/qgpgmekeygenerationjob.h
new file mode 100644
index 0000000..6203960
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp 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..6059941
--- /dev/null
+++ b/lang/qt/src/qgpgmekeylistjob.cpp
@@ -0,0 +1,167 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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 boost::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 boost::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 boost::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 boost::make_tuple(result, keys, QString(), Error());
+}
+
+Error QGpgMEKeyListJob::start(const QStringList &patterns, bool secretOnly)
+{
+    mSecretOnly = secretOnly;
+    run(boost::bind(&list_keys, _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 = get<1>(r);
+    return get<0>(r);
+}
+
+void QGpgMEKeyListJob::resultHook(const result_type &tuple)
+{
+    mResult = get<0>(tuple);
+    Q_FOREACH (const Key &key, get<1>(tuple)) {
+        Q_EMIT nextKey(key);
+    }
+}
+#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
diff --git a/lang/qt/src/qgpgmekeylistjob.h b/lang/qt/src/qgpgmekeylistjob.h
new file mode 100644
index 0000000..860bb3e
--- /dev/null
+++ b/lang/qt/src/qgpgmekeylistjob.h
@@ -0,0 +1,90 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from KeyListJob */
+    GpgME::Error start(const QStringList &patterns, bool secretOnly) Q_DECL_OVERRIDE;
+
+    /*! \reimp from KeyListJob */
+    GpgME::KeyListResult exec(const QStringList &patterns, bool secretOnly, std::vector<GpgME::Key> &keys) Q_DECL_OVERRIDE;
+
+    /*! \reimp from Job */
+    void showErrorDialog(QWidget *parent, const QString &caption) const Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..a51231f
--- /dev/null
+++ b/lang/qt/src/qgpgmelistallkeysjob.cpp
@@ -0,0 +1,170 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 "predicates.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;
+using namespace boost;
+
+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),
+               _detail::ByFingerprint<std::less>());
+
+    merged.erase(unique_by_merge(merged.begin(), merged.end(), _detail::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(), _detail::ByFingerprint<std::less>());
+
+    r.mergeWith(do_list_keys(ctx, sec, true));
+    std::sort(sec.begin(), sec.end(), _detail::ByFingerprint<std::less>());
+
+    if (mergeKeys) {
+        merge_keys(merged, pub, sec);
+    } else {
+        merged.swap(pub);
+    }
+    return boost::make_tuple(r, merged, sec, QString(), Error());
+}
+
+Error QGpgMEListAllKeysJob::start(bool mergeKeys)
+{
+    run(boost::bind(&list_keys, _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 = get<1>(r);
+    sec = get<2>(r);
+    return get<0>(r);
+}
+
+void QGpgMEListAllKeysJob::resultHook(const result_type &tuple)
+{
+    mResult = 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
diff --git a/lang/qt/src/qgpgmelistallkeysjob.h b/lang/qt/src/qgpgmelistallkeysjob.h
new file mode 100644
index 0000000..f7aabf5
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from ListAllKeysJob */
+    GpgME::Error start(bool mergeKeys) Q_DECL_OVERRIDE;
+
+    /*! \reimp from ListAllKeysJob */
+    GpgME::KeyListResult exec(std::vector<GpgME::Key> &pub, std::vector<GpgME::Key> &sec, bool mergeKeys) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..13017d6
--- /dev/null
+++ b/lang/qt/src/qgpgmenewcryptoconfig.cpp
@@ -0,0 +1,742 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <boost/mem_fn.hpp>
+
+#include <sstream>
+#include <string>
+#include <cassert>
+
+using namespace boost;
+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
+    BOOST_FOREACH(const Component & c, components) {
+        const 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)
+{
+    BOOST_FOREACH(const 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();
+
+    shared_ptr<QGpgMENewCryptoConfigGroup> group;
+
+    const std::vector<Option> options = m_component.options();
+    BOOST_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 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),
+                   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 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 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 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 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;
+    BOOST_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..0afe381
--- /dev/null
+++ b/lang/qt/src/qgpgmenewcryptoconfig.h
@@ -0,0 +1,192 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <vector>
+#include <utility>
+
+class QGpgMENewCryptoConfig;
+class QGpgMENewCryptoConfigComponent;
+class QGpgMENewCryptoConfigGroup;
+class QGpgMENewCryptoConfigEntry;
+
+class QGpgMENewCryptoConfigEntry : public QGpgME::CryptoConfigEntry
+{
+public:
+    QGpgMENewCryptoConfigEntry(const boost::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:
+    boost::weak_ptr<QGpgMENewCryptoConfigGroup> m_group;
+    GpgME::Configuration::Option m_option;
+};
+
+class QGpgMENewCryptoConfigGroup : public QGpgME::CryptoConfigGroup
+{
+public:
+    QGpgMENewCryptoConfigGroup(const boost::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
+    boost::weak_ptr<QGpgMENewCryptoConfigComponent> m_component;
+    GpgME::Configuration::Option m_option;
+    QStringList m_entryNames;
+    QHash< QString, boost::shared_ptr<QGpgMENewCryptoConfigEntry> > m_entriesByName;
+};
+
+/// For docu, see kleo/cryptoconfig.h
+class QGpgMENewCryptoConfigComponent : public QGpgME::CryptoConfigComponent, public boost::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, boost::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, boost::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..2a35b23
--- /dev/null
+++ b/lang/qt/src/qgpgmerefreshkeysjob.cpp
@@ -0,0 +1,224 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+        const int typ = (*++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();
+}
diff --git a/lang/qt/src/qgpgmerefreshkeysjob.h b/lang/qt/src/qgpgmerefreshkeysjob.h
new file mode 100644
index 0000000..bf4fbb2
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp from RefreshKeysJob */
+    GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    /*! \reimp 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..9fd3ffe
--- /dev/null
+++ b/lang/qt/src/qgpgmesecretkeyexportjob.cpp
@@ -0,0 +1,141 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+}
diff --git a/lang/qt/src/qgpgmesecretkeyexportjob.h b/lang/qt/src/qgpgmesecretkeyexportjob.h
new file mode 100644
index 0000000..13b2e0d
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp from ExportJob */
+    GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+    /*! \reimp 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..1712b38
--- /dev/null
+++ b/lang/qt/src/qgpgmesignencryptjob.cpp
@@ -0,0 +1,160 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+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 weak_ptr<QIODevice> &plainText_, const weak_ptr<QIODevice> &cipherText_, bool alwaysTrust, bool outputIsBsse64Encoded)
+{
+    const shared_ptr<QIODevice> &plainText = plainText_.lock();
+    const 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);
+
+    const Context::EncryptionFlags eflags =
+        alwaysTrust ? Context::AlwaysTrust : Context::None;
+
+    ctx->clearSigningKeys();
+    Q_FOREACH (const Key &signer, signers)
+        if (!signer.isNull())
+            if (const Error err = ctx->addSigningKey(signer)) {
+                return 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 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 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, bool alwaysTrust, bool outputIsBsse64Encoded)
+{
+    const 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, shared_ptr<QIODevice>(), alwaysTrust, outputIsBsse64Encoded);
+}
+
+Error QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
+{
+    run(boost::bind(&sign_encrypt_qba, _1, signers, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded));
+    return Error();
+}
+
+void QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const shared_ptr<QIODevice> &plainText, const shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+{
+    run(boost::bind(&sign_encrypt, _1, _2, signers, recipients, _3, _4, alwaysTrust, mOutputIsBase64Encoded), plainText, cipherText);
+}
+
+std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+    const result_type r = sign_encrypt_qba(context(), signers, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded);
+    cipherText = get<2>(r);
+    resultHook(r);
+    return mResult;
+}
+
+#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(get<0>(tuple), get<1>(tuple));
+}
diff --git a/lang/qt/src/qgpgmesignencryptjob.h b/lang/qt/src/qgpgmesignencryptjob.h
new file mode 100644
index 0000000..d04661a
--- /dev/null
+++ b/lang/qt/src/qgpgmesignencryptjob.h
@@ -0,0 +1,109 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp 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;
+
+    /*! \reimp from SignEncryptJob */
+    void start(const std::vector<GpgME::Key> &signers,
+               const std::vector<GpgME::Key> &recipients,
+               const boost::shared_ptr<QIODevice> &plainText,
+               const boost::shared_ptr<QIODevice> &cipherText,
+               bool alwaysTrust) 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;
+
+    /*! \reimp from SignEncryptJob */
+    void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..5d8ae85
--- /dev/null
+++ b/lang/qt/src/qgpgmesignjob.cpp
@@ -0,0 +1,164 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+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 weak_ptr<QIODevice> &plainText_,
+                                       const weak_ptr<QIODevice> &signature_,
+                                       SignatureMode mode,
+                                       bool outputIsBsse64Encoded)
+{
+
+    const shared_ptr<QIODevice> plainText = plainText_.lock();
+    const 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 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 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 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 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, shared_ptr<QIODevice>(), mode, outputIsBsse64Encoded);
+}
+
+Error QGpgMESignJob::start(const std::vector<Key> &signers, const QByteArray &plainText, SignatureMode mode)
+{
+    run(boost::bind(&sign_qba, _1, signers, plainText, mode, mOutputIsBase64Encoded));
+    return Error();
+}
+
+void QGpgMESignJob::start(const std::vector<Key> &signers, const shared_ptr<QIODevice> &plainText, const shared_ptr<QIODevice> &signature, SignatureMode mode)
+{
+    run(boost::bind(&sign, _1, _2, signers, _3, _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 = get<1>(r);
+    resultHook(r);
+    return mResult;
+}
+
+void QGpgMESignJob::resultHook(const result_type &tuple)
+{
+    mResult = 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
diff --git a/lang/qt/src/qgpgmesignjob.h b/lang/qt/src/qgpgmesignjob.h
new file mode 100644
index 0000000..2f574f8
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from SignJob */
+    GpgME::Error start(const std::vector<GpgME::Key> &signers,
+                       const QByteArray &plainText,
+                       GpgME::SignatureMode mode) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignJob */
+    void start(const std::vector<GpgME::Key> &signers,
+               const boost::shared_ptr<QIODevice> &plainText,
+               const boost::shared_ptr<QIODevice> &signature,
+               GpgME::SignatureMode mode) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignJob */
+    GpgME::SigningResult exec(const std::vector<GpgME::Key> &signers,
+                              const QByteArray &plainText,
+                              GpgME::SignatureMode mode,
+                              QByteArray &signature) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignJob */
+    void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..c6bbe2c
--- /dev/null
+++ b/lang/qt/src/qgpgmesignkeyjob.cpp
@@ -0,0 +1,127 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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;
+using namespace boost;
+
+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);
+
+    std::auto_ptr<GpgSignKeyEditInteractor> skei(new GpgSignKeyEditInteractor);
+    skei->setUserIDsToSign(uids);
+    skei->setCheckLevel(checkLevel);
+    skei->setSigningOptions(opts);
+
+    std::auto_ptr<EditInteractor> ei(skei);
+
+    if (!signer.isNull())
+        if (const Error err = ctx->addSigningKey(signer)) {
+            return make_tuple(err, QString(), Error());
+        }
+    const Error err = ctx->edit(key, ei, data);
+    Error ae;
+    const QString log = _detail::audit_log_as_html(ctx, ae);
+    return 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(boost::bind(&sign_key, _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;
+}
diff --git a/lang/qt/src/qgpgmesignkeyjob.h b/lang/qt/src/qgpgmesignkeyjob.h
new file mode 100644
index 0000000..aa3592a
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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();
+
+    /*! \reimp from SignKeyJob */
+    GpgME::Error start(const GpgME::Key &key) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignKeyJob */
+    void setUserIDsToSign(const std::vector<unsigned int> &idsToSign) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignKeyJob */
+    void setCheckLevel(unsigned int checkLevel) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignKeyJob */
+    void setExportable(bool exportable) Q_DECL_OVERRIDE;
+
+    /*! \reimp from SignKeyJob */
+    void setSigningKey(const GpgME::Key &key) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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/qgpgmeverifydetachedjob.cpp b/lang/qt/src/qgpgmeverifydetachedjob.cpp
new file mode 100644
index 0000000..5122835
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifydetachedjob.cpp
@@ -0,0 +1,119 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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>
+
+#include <boost/weak_ptr.hpp>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+QGpgMEVerifyDetachedJob::QGpgMEVerifyDetachedJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEVerifyDetachedJob::~QGpgMEVerifyDetachedJob() {}
+
+static QGpgMEVerifyDetachedJob::result_type verify_detached(Context *ctx, QThread *thread, const weak_ptr<QIODevice> &signature_, const weak_ptr<QIODevice> &signedData_)
+{
+    const shared_ptr<QIODevice> signature = signature_.lock();
+    const 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 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 make_tuple(res, log, ae);
+
+}
+
+Error QGpgMEVerifyDetachedJob::start(const QByteArray &signature, const QByteArray &signedData)
+{
+    run(bind(&verify_detached_qba, _1, signature, signedData));
+    return Error();
+}
+
+void QGpgMEVerifyDetachedJob::start(const shared_ptr<QIODevice> &signature, const shared_ptr<QIODevice> &signedData)
+{
+    run(bind(&verify_detached, _1, _2, _3, _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 = get<0>(tuple);
+}
diff --git a/lang/qt/src/qgpgmeverifydetachedjob.h b/lang/qt/src/qgpgmeverifydetachedjob.h
new file mode 100644
index 0000000..db502be
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from VerifyDetachedJob */
+    GpgME::Error start(const QByteArray &signature, const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+    /*! \reimp from VerifyDetachedJob */
+    void start(const boost::shared_ptr<QIODevice> &signature, const boost::shared_ptr<QIODevice> &signedData) Q_DECL_OVERRIDE;
+
+    /*! \reimp from VerifyDetachedJob */
+    GpgME::VerificationResult exec(const QByteArray &signature,
+                                   const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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..fd5b708
--- /dev/null
+++ b/lang/qt/src/qgpgmeverifyopaquejob.cpp
@@ -0,0 +1,126 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/weak_ptr.hpp>
+
+#include <cassert>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+QGpgMEVerifyOpaqueJob::QGpgMEVerifyOpaqueJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEVerifyOpaqueJob::~QGpgMEVerifyOpaqueJob() {}
+
+static QGpgMEVerifyOpaqueJob::result_type verify_opaque(Context *ctx, QThread *thread, const weak_ptr<QIODevice> &signedData_, const weak_ptr<QIODevice> &plainText_)
+{
+
+    const shared_ptr<QIODevice> plainText = plainText_.lock();
+    const 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 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 make_tuple(res, QByteArray(), log, ae);
+    }
+
+}
+
+static QGpgMEVerifyOpaqueJob::result_type verify_opaque_qba(Context *ctx, const QByteArray &signedData)
+{
+    const 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, shared_ptr<QIODevice>());
+}
+
+Error QGpgMEVerifyOpaqueJob::start(const QByteArray &signedData)
+{
+    run(bind(&verify_opaque_qba, _1, signedData));
+    return Error();
+}
+
+void QGpgMEVerifyOpaqueJob::start(const shared_ptr<QIODevice> &signedData, const shared_ptr<QIODevice> &plainText)
+{
+    run(bind(&verify_opaque, _1, _2, _3, _4), signedData, plainText);
+}
+
+GpgME::VerificationResult QGpgME::QGpgMEVerifyOpaqueJob::exec(const QByteArray &signedData, QByteArray &plainText)
+{
+    const result_type r = verify_opaque_qba(context(), signedData);
+    plainText = get<1>(r);
+    resultHook(r);
+    return mResult;
+}
+
+//PENDING(marc) implement showErrorDialog()
+
+void QGpgME::QGpgMEVerifyOpaqueJob::resultHook(const result_type &tuple)
+{
+    mResult = get<0>(tuple);
+}
diff --git a/lang/qt/src/qgpgmeverifyopaquejob.h b/lang/qt/src/qgpgmeverifyopaquejob.h
new file mode 100644
index 0000000..daec5d2
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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, boost::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();
+
+    /*! \reimp from VerifyOpaqueJob */
+    GpgME::Error start(const QByteArray &signedData) Q_DECL_OVERRIDE;
+
+    /*! \reimp from VerifyOpaqueJob */
+    void start(const boost::shared_ptr<QIODevice> &signedData, const boost::shared_ptr<QIODevice> &plainText) Q_DECL_OVERRIDE;
+
+    /*! \reimp form VerifyOpaqueJob */
+    GpgME::VerificationResult exec(const QByteArray &signedData, QByteArray &plainData) Q_DECL_OVERRIDE;
+
+    /*! \reimp 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/refreshkeysjob.h b/lang/qt/src/refreshkeysjob.h
new file mode 100644
index 0000000..ca2ee5c
--- /dev/null
+++ b/lang/qt/src/refreshkeysjob.h
@@ -0,0 +1,93 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <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 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..9dba4be
--- /dev/null
+++ b/lang/qt/src/signencryptjob.h
@@ -0,0 +1,136 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+#ifdef BUILDING_QGPGME
+# include "global.h"
+#else
+# include <gpgme++/global.h>
+#endif
+
+#include <boost/shared_ptr.hpp>
+
+#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 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 boost::shared_ptr<QIODevice> &plainText,
+                       const boost::shared_ptr<QIODevice> &cipherText = boost::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;
+
+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..babe4d0
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+#include <vector>
+
+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 boost::shared_ptr<QIODevice> &plainText,
+                       const boost::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..9786897
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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..c0076c2
--- /dev/null
+++ b/lang/qt/src/specialjob.h
@@ -0,0 +1,90 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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"
+
+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 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..5b07245
--- /dev/null
+++ b/lang/qt/src/threadedjobmixin.cpp
@@ -0,0 +1,112 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/mem_fn.hpp>
+
+#include <algorithm>
+#include <iterator>
+
+using namespace QGpgME;
+using namespace GpgME;
+using namespace boost;
+
+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,
+                                          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..2421439
--- /dev/null
+++ b/lang/qt/src/threadedjobmixin.h
@@ -0,0 +1,280 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#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 boost::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 boost::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;
+    boost::function<T_result()> m_function;
+    T_result m_result;
+};
+
+template <typename T_base, typename T_result = boost::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:
+    BOOST_STATIC_ASSERT((boost::tuples::length<T_result>::value > 2));
+    BOOST_STATIC_ASSERT((
+                            boost::is_same <
+                            typename boost::tuples::element <
+                            boost::tuples::length<T_result>::value - 2,
+                            T_result
+                            >::type,
+                            QString
+                            >::value
+                        ));
+    BOOST_STATIC_ASSERT((
+                            boost::is_same <
+                            typename boost::tuples::element <
+                            boost::tuples::length<T_result>::value - 1,
+                            T_result
+                            >::type,
+                            GpgME::Error
+                            >::value
+                        ));
+
+    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(boost::bind(func, this->context()));
+        m_thread.start();
+    }
+    template <typename T_binder>
+    void run(const T_binder &func, const boost::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 weak_ptr's to the functor.
+        m_thread.setFunction(boost::bind(func, this->context(), this->thread(), boost::weak_ptr<QIODevice>(io)));
+        m_thread.start();
+    }
+    template <typename T_binder>
+    void run(const T_binder &func, const boost::shared_ptr<QIODevice> &io1, const boost::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 weak_ptr's to the functor.
+        m_thread.setFunction(boost::bind(func, this->context(), this->thread(), boost::weak_ptr<QIODevice>(io1), boost::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 = boost::get < boost::tuples::length<T_result>::value - 2 > (r);
+        m_auditLogError = boost::get < boost::tuples::length<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 boost::tuple<T1, T2> &tuple)
+    {
+        Q_EMIT this->result(boost::get<0>(tuple), boost::get<1>(tuple));
+    }
+
+    template <typename T1, typename T2, typename T3>
+    void doEmitResult(const boost::tuple<T1, T2, T3> &tuple)
+    {
+        Q_EMIT this->result(boost::get<0>(tuple), boost::get<1>(tuple), boost::get<2>(tuple));
+    }
+
+    template <typename T1, typename T2, typename T3, typename T4>
+    void doEmitResult(const boost::tuple<T1, T2, T3, T4> &tuple)
+    {
+        Q_EMIT this->result(boost::get<0>(tuple), boost::get<1>(tuple), boost::get<2>(tuple), boost::get<3>(tuple));
+    }
+
+    template <typename T1, typename T2, typename T3, typename T4, typename T5>
+    void doEmitResult(const boost::tuple<T1, T2, T3, T4, T5> &tuple)
+    {
+        Q_EMIT this->result(boost::get<0>(tuple), boost::get<1>(tuple), boost::get<2>(tuple), boost::get<3>(tuple), boost::get<4>(tuple));
+    }
+
+private:
+    boost::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/verifydetachedjob.h b/lang/qt/src/verifydetachedjob.h
new file mode 100644
index 0000000..ba574f6
--- /dev/null
+++ b/lang/qt/src/verifydetachedjob.h
@@ -0,0 +1,98 @@
+/*
+    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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+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 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 boost::shared_ptr<QIODevice> &signature, const boost::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..cdb1cf6
--- /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
+
+    Libkleopatra 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.
+
+    Libkleopatra is distributed in the hope that 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 <boost/shared_ptr.hpp>
+
+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 boost::shared_ptr<QIODevice> &signedData, const boost::shared_ptr<QIODevice> &plainText = boost::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__

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



More information about the Pkg-gnupg-commit mailing list