[git] GPGME - branch, master, updated. gpgme-1.6.0-265-gf209ec8

by Andre Heinecke cvs at cvs.gnupg.org
Tue Aug 9 14:24:31 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  f209ec8f581ae597b37f2e3a5e452e4b53b2d4c7 (commit)
       via  34b456c3fb9e59788b07a75441da482bb28bda87 (commit)
       via  17372393798ea5e2d6838f3dd1e001dd4a66c941 (commit)
       via  bf776ce94cf454f1b3f1645b1cde09cd1c54324b (commit)
       via  3d2f027d0f40e7ec4ab48cee89ff0ee10b423566 (commit)
      from  b5e16b036f0045524a583d8a366d8a3366fc0005 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f209ec8f581ae597b37f2e3a5e452e4b53b2d4c7
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 9 14:10:15 2016 +0200

    Qt: Add encryption test and refactor testsuite
    
    * lang/qt/tests/Makefile.am: Add t-encrypt and t-support.
    * lang/qt/tests/t-support.cpp, lang/qt/tests/t-support.c (QGpgMETest):
    New. Class to handle common cleanup / init.
    * lang/qt/tests/t-keylist.cpp,
    lang/qt/tests/t-keylocate.cpp,
    lang/qt/tests/t-ownertrust.cpp,
    lang/qt/tests/t-tofuinfo.cpp: Inherit QGpgMETest.
    * lang/qt/tests/t-encrypt.cpp: New. Test Symetric and Asymectric
    encryption. Mixed encryption test is disabled.

diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
index 348c05b..13495a8 100644
--- a/lang/qt/tests/Makefile.am
+++ b/lang/qt/tests/Makefile.am
@@ -24,9 +24,11 @@ TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir)
 
 EXTRA_DIST = initial.test
 
-TESTS = initial.test t-keylist t-keylocate t-ownertrust t-tofuinfo
+TESTS = initial.test t-keylist t-keylocate t-ownertrust t-tofuinfo \
+        t-encrypt
 
-moc_files = t-keylist.moc t-keylocate.moc t-ownertrust.moc t-tofuinfo.moc
+moc_files = t-keylist.moc t-keylocate.moc t-ownertrust.moc t-tofuinfo.moc \
+            t-encrypt.moc t-support.hmoc
 
 AM_LDFLAGS = -no-install
 
@@ -46,16 +48,19 @@ check-local: ./pubring-stamp
 # add this dependency:
 initial.test : check-local
 
-t_keylist_SOURCES = t-keylist.cpp
-t_keylocate_SOURCES = t-keylocate.cpp
-t_ownertrust_SOURCES = t-ownertrust.cpp
-t_tofuinfo_SOURCES = t-tofuinfo.cpp t-support.h
+support_src = t-support.h t-support.cpp
+
+t_keylist_SOURCES = t-keylist.cpp $(support_src)
+t_keylocate_SOURCES = t-keylocate.cpp $(support_src)
+t_ownertrust_SOURCES = t-ownertrust.cpp $(support_src)
+t_tofuinfo_SOURCES = t-tofuinfo.cpp $(support_src)
+t_encrypt_SOURCES = t-encrypt.cpp $(support_src)
 
 nodist_t_keylist_SOURCES = $(moc_files)
 
 BUILT_SOURCES = $(moc_files)
 
-noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo
+noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt
 
 CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
 	gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
@@ -82,3 +87,6 @@ export GNUPGHOME := $(abs_builddir)
 
 .cpp.moc:
 	$(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
+
+.h.hmoc:
+	$(MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@
diff --git a/lang/qt/tests/t-encrypt.cpp b/lang/qt/tests/t-encrypt.cpp
new file mode 100644
index 0000000..b0b6994
--- /dev/null
+++ b/lang/qt/tests/t-encrypt.cpp
@@ -0,0 +1,194 @@
+/* t-encrypt.cpp
+
+    This file is part of qgpgme, the Qt API binding for gpgme
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+#include <QDebug>
+#include <QTest>
+#include <QTemporaryDir>
+#include "keylistjob.h"
+#include "encryptjob.h"
+#include "qgpgmeencryptjob.h"
+#include "encryptionresult.h"
+#include "decryptionresult.h"
+#include "qgpgmedecryptjob.h"
+#include "qgpgmebackend.h"
+#include "keylistresult.h"
+#include "t-support.h"
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class EncryptionTest : public QGpgMETest
+{
+    Q_OBJECT
+
+private Q_SLOTS:
+
+    void testSimpleEncryptDecrypt()
+    {
+        auto listjob = openpgp()->keyListJob(false, false, false);
+        std::vector<Key> keys;
+        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa at example.net"),
+                                          false, keys);
+        Q_ASSERT(!keylistresult.error());
+        Q_ASSERT(keys.size() == 1);
+        delete listjob;
+
+        auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
+        Q_ASSERT(job);
+        QByteArray cipherText;
+        auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
+        delete job;
+        Q_ASSERT(!result.error());
+        const auto cipherString = QString::fromUtf8(cipherText);
+        Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+        /* Now decrypt */
+        auto ctx = Context::createForProtocol(OpenPGP);
+        ctx->setPassphraseProvider(new TestPassphraseProvider);
+        ctx->setPinentryMode(Context::PinentryLoopback);
+        auto decJob = new QGpgMEDecryptJob(ctx);
+        QByteArray plainText;
+        auto decResult = decJob->exec(cipherText, plainText);
+        Q_ASSERT(!result.error());
+        Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
+        delete decJob;
+    }
+
+    void testSymmetricEncryptDecrypt()
+    {
+        auto ctx = Context::createForProtocol(OpenPGP);
+        ctx->setPassphraseProvider(new TestPassphraseProvider);
+        ctx->setPinentryMode(Context::PinentryLoopback);
+        ctx->setArmor(true);
+        ctx->setTextMode(true);
+        auto job = new QGpgMEEncryptJob(ctx);
+        QByteArray cipherText;
+        auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
+        delete job;
+        Q_ASSERT(!result.error());
+        const auto cipherString = QString::fromUtf8(cipherText);
+        Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+        killAgent(mDir.path());
+
+        auto ctx2 = Context::createForProtocol(OpenPGP);
+        ctx2->setPassphraseProvider(new TestPassphraseProvider);
+        ctx2->setPinentryMode(Context::PinentryLoopback);
+        auto decJob = new QGpgMEDecryptJob(ctx2);
+        QByteArray plainText;
+        auto decResult = decJob->exec(cipherText, plainText);
+        Q_ASSERT(!result.error());
+        Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
+        delete decJob;
+    }
+
+private:
+    /* Loopback and passphrase provider don't work for mixed encryption.
+     * So this test is disabled until gnupg(?) is fixed for this. */
+    void testMixedEncryptDecrypt()
+    {
+        auto listjob = openpgp()->keyListJob(false, false, false);
+        std::vector<Key> keys;
+        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa at example.net"),
+                                          false, keys);
+        Q_ASSERT(!keylistresult.error());
+        Q_ASSERT(keys.size() == 1);
+        delete listjob;
+
+        auto ctx = Context::createForProtocol(OpenPGP);
+        ctx->setPassphraseProvider(new TestPassphraseProvider);
+        ctx->setPinentryMode(Context::PinentryLoopback);
+        ctx->setArmor(true);
+        ctx->setTextMode(true);
+        auto job = new QGpgMEEncryptJob(ctx);
+        QByteArray cipherText;
+        printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
+        auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
+                                static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
+                                cipherText);
+        printf("After exec\n");
+        delete job;
+        Q_ASSERT(!result.error());
+        printf("Cipher:\n%s\n", cipherText.constData());
+        const auto cipherString = QString::fromUtf8(cipherText);
+        Q_ASSERT(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
+
+        killAgent(mDir.path());
+
+        /* Now create a new homedir which with we test symetric decrypt. */
+        QTemporaryDir tmp;
+        qputenv("GNUPGHOME", tmp.path().toUtf8());
+        QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
+        Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+        agentConf.write("allow-loopback-pinentry");
+        agentConf.close();
+
+        auto ctx2 = Context::createForProtocol(OpenPGP);
+        ctx2->setPassphraseProvider(new TestPassphraseProvider);
+        ctx2->setPinentryMode(Context::PinentryLoopback);
+        ctx2->setTextMode(true);
+        auto decJob = new QGpgMEDecryptJob(ctx2);
+        QByteArray plainText;
+        auto decResult = decJob->exec(cipherText, plainText);
+        Q_ASSERT(!decResult.error());
+        qDebug() << "Plain: " << plainText;
+        Q_ASSERT(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
+        delete decJob;
+
+        killAgent(tmp.path());
+        qputenv("GNUPGHOME", mDir.path().toUtf8());
+    }
+
+public Q_SLOT:
+
+    void initTestCase()
+    {
+        QGpgMETest::initTestCase();
+        const QString gpgHome = qgetenv("GNUPGHOME");
+        qputenv("GNUPGHOME", mDir.path().toUtf8());
+        Q_ASSERT(mDir.isValid());
+        QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
+        Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
+        agentConf.write("allow-loopback-pinentry");
+        agentConf.close();
+        Q_ASSERT(QFile::copy(gpgHome + QStringLiteral("/pubring.gpg"),
+                 mDir.path() + QStringLiteral("/pubring.gpg")));
+        Q_ASSERT(QFile::copy(gpgHome + QStringLiteral("/secring.gpg"),
+                 mDir.path() + QStringLiteral("/secring.gpg")));
+
+    }
+
+private:
+    QTemporaryDir mDir;
+};
+
+QTEST_MAIN(EncryptionTest)
+
+#include "t-encrypt.moc"
diff --git a/lang/qt/tests/t-keylist.cpp b/lang/qt/tests/t-keylist.cpp
index adc997a..2fbec28 100644
--- a/lang/qt/tests/t-keylist.cpp
+++ b/lang/qt/tests/t-keylist.cpp
@@ -37,10 +37,12 @@
 #include "qgpgmebackend.h"
 #include "keylistresult.h"
 
+#include "t-support.h"
+
 using namespace QGpgME;
 using namespace GpgME;
 
-class KeyListTest : public QObject
+class KeyListTest : public QGpgMETest
 {
     Q_OBJECT
 
@@ -48,7 +50,6 @@ Q_SIGNALS:
     void asyncDone();
 
 private Q_SLOTS:
-
     void testSingleKeyListSync()
     {
         KeyListJob *job = openpgp()->keyListJob(false, false, false);
@@ -99,19 +100,9 @@ private Q_SLOTS:
         QSignalSpy spy (this, SIGNAL(asyncDone()));
         Q_ASSERT(spy.wait());
     }
-
-    void initTestCase()
-    {
-        const QString gpgHome = qgetenv("GNUPGHOME");
-        QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
-    }
-
-    void cleanupTestCase()
-    {
-        QCoreApplication::sendPostedEvents();
-    }
 };
 
 QTEST_MAIN(KeyListTest)
 
 #include "t-keylist.moc"
+#include "t-support.moc"
diff --git a/lang/qt/tests/t-keylocate.cpp b/lang/qt/tests/t-keylocate.cpp
index 5f52cc3..e75f24d 100644
--- a/lang/qt/tests/t-keylocate.cpp
+++ b/lang/qt/tests/t-keylocate.cpp
@@ -37,10 +37,12 @@
 #include "keylistresult.h"
 #include "engineinfo.h"
 
+#include "t-support.h"
+
 using namespace QGpgME;
 using namespace GpgME;
 
-class KeyLocateTest : public QObject
+class KeyLocateTest : public QGpgMETest
 {
     Q_OBJECT
 
@@ -119,16 +121,6 @@ private Q_SLOTS:
         Q_ASSERT(spy.wait());
     }
 
-    void initTestCase()
-    {
-        const QString gpgHome = qgetenv("GNUPGHOME");
-        QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
-    }
-
-    void cleanupTestCase()
-    {
-        QCoreApplication::sendPostedEvents();
-    }
 private:
     QString mTestpattern;
 };
diff --git a/lang/qt/tests/t-ownertrust.cpp b/lang/qt/tests/t-ownertrust.cpp
index 8784a79..b9efffd 100644
--- a/lang/qt/tests/t-ownertrust.cpp
+++ b/lang/qt/tests/t-ownertrust.cpp
@@ -37,10 +37,12 @@
 #include "keylistresult.h"
 #include "changeownertrustjob.h"
 
+#include "t-support.h"
+
 using namespace QGpgME;
 using namespace GpgME;
 
-class ChangeOwnerTrustTest: public QObject
+class ChangeOwnerTrustTest: public QGpgMETest
 {
     Q_OBJECT
 
@@ -98,17 +100,6 @@ private Q_SLOTS:
         key = keys.front();
         Q_ASSERT (key.ownerTrust() == Key::Unknown);
     }
-
-    void initTestCase()
-    {
-        const QString gpgHome = qgetenv("GNUPGHOME");
-        QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
-    }
-
-    void cleanupTestCase()
-    {
-        QCoreApplication::sendPostedEvents();
-    }
 };
 
 QTEST_MAIN(ChangeOwnerTrustTest)
diff --git a/lang/qt/tests/t-support.h b/lang/qt/tests/t-support.cpp
similarity index 66%
copy from lang/qt/tests/t-support.h
copy to lang/qt/tests/t-support.cpp
index 8755b99..202a251 100644
--- a/lang/qt/tests/t-support.h
+++ b/lang/qt/tests/t-support.cpp
@@ -1,4 +1,4 @@
-/* t-support.h
+/* t-support.cpp
 
     This file is part of qgpgme, the Qt API binding for gpgme
     Copyright (c) 2016 Intevation GmbH
@@ -29,19 +29,35 @@
     your version.
 */
 
-#include "interfaces/passphraseprovider.h"
-#include <QtGlobal>
+#include "t-support.h"
 
-namespace GpgME
+#include <QTest>
+
+void QGpgMETest::initTestCase()
+{
+    const QString gpgHome = qgetenv("GNUPGHOME");
+    QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
+}
+
+void QGpgMETest::cleanupTestCase()
 {
-class TestPassphraseProvider : public PassphraseProvider
+    QCoreApplication::sendPostedEvents();
+    killAgent();
+    printf("Killed agent\n");
+}
+#include <QDebug>
+void killAgent(const QString& dir)
 {
-public:
-    char *getPassphrase(const char *useridHint, const char *description,
-                        bool previousWasBad, bool &canceled) Q_DECL_OVERRIDE
-    {
-        return strdup("abc");
-    }
-};
-
-} // namespace GpgME
+    QProcess proc;
+    proc.setProgram(QStringLiteral("gpg-connect-agent"));
+    QStringList arguments;
+    arguments << "-S " << dir + "/S.gpg-agent";
+    proc.start();
+    proc.waitForStarted();
+    proc.write("KILLAGENT\n");
+    proc.write("BYE\n");
+    proc.closeWriteChannel();
+    proc.waitForFinished();
+}
+
+#include "t-support.hmoc"
diff --git a/lang/qt/tests/t-support.h b/lang/qt/tests/t-support.h
index 8755b99..cf0cb26 100644
--- a/lang/qt/tests/t-support.h
+++ b/lang/qt/tests/t-support.h
@@ -28,9 +28,14 @@
     you do not wish to do so, delete this exception statement from
     your version.
 */
+#ifndef T_SUPPORT_H
+#define T_SUPPORT_H
 
 #include "interfaces/passphraseprovider.h"
 #include <QtGlobal>
+#include <QProcess>
+#include <QCoreApplication>
+#include <QObject>
 
 namespace GpgME
 {
@@ -43,5 +48,17 @@ public:
         return strdup("abc");
     }
 };
-
 } // namespace GpgME
+
+void killAgent(const QString &dir = qgetenv("GNUPGHOME"));
+
+class QGpgMETest : public QObject
+{
+    Q_OBJECT
+
+public Q_SLOTS:
+    void initTestCase();
+    void cleanupTestCase();
+};
+
+#endif // T_SUPPORT_H
diff --git a/lang/qt/tests/t-tofuinfo.cpp b/lang/qt/tests/t-tofuinfo.cpp
index f9634b2..8331092 100644
--- a/lang/qt/tests/t-tofuinfo.cpp
+++ b/lang/qt/tests/t-tofuinfo.cpp
@@ -55,7 +55,7 @@ static const char testMsg1[] =
 "=Crq6\n"
 "-----END PGP MESSAGE-----\n";
 
-class TofuInfoTest: public QObject
+class TofuInfoTest: public QGpgMETest
 {
     Q_OBJECT
 
@@ -216,8 +216,8 @@ private /* FIXME Disabled until GnuPG-Bug-Id 2405 is fixed Q_SLOTS */:
 
     void initTestCase()
     {
+        QGpgMETest::initTestCase();
         const QString gpgHome = qgetenv("GNUPGHOME");
-        QVERIFY2(!gpgHome.isEmpty(), "GNUPGHOME environment variable is not set.");
         qputenv("GNUPGHOME", mDir.path().toUtf8());
         Q_ASSERT(mDir.isValid());
         QFile conf(mDir.path() + QStringLiteral("/gpg.conf"));

commit 34b456c3fb9e59788b07a75441da482bb28bda87
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 9 13:10:08 2016 +0200

    Qt: Add support for EncryptJobs with generic flags
    
    * lang/qt/src/encryptjob.h, lang/qt/src/signencryptjob.h,
    lang/qt/src/qgpgmeencryptjob.h, lang/qt/src/qgpgmeencryptjob.cpp,
    lang/qt/src/qgpgmesignencryptjob.cpp,
    lang/qt/src/qgpgmeencryptjob.cpp: Add start and exec overloads
    that accept generic EncryptFlags.
    
    --
    While this technically is an ABI break (vtable change) there
    are no known classes outside qgpgme that inherit encryptjob
    or signencryptjob. And the new functions should be added
    to the bottom of the vtable.

diff --git a/lang/qt/src/encryptjob.h b/lang/qt/src/encryptjob.h
index 060ff8d..4ff9c82 100644
--- a/lang/qt/src/encryptjob.h
+++ b/lang/qt/src/encryptjob.h
@@ -39,6 +39,12 @@
 #include <memory>
 #include <vector>
 
+#ifdef BUILDING_QGPGME
+# include "context.h"
+#else
+# include <gpgme++/context.h>
+#endif
+
 class QByteArray;
 class QIODevice;
 
@@ -103,13 +109,24 @@ public:
     virtual GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
                                          const QByteArray &plainText,
                                          bool alwaysTrust, QByteArray &cipherText) = 0;
-
     /*!
       This is a hack to request BASE64 output (instead of whatever
       comes out normally).
     */
     virtual void setOutputIsBase64Encoded(bool) = 0;
 
+    /** Like start but with an additional argument for EncryptionFlags for
+     * more flexibility. */
+    virtual void start(const std::vector<GpgME::Key> &recipients,
+                       const std::shared_ptr<QIODevice> &plainText,
+                       const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+                       const GpgME::Context::EncryptionFlags flags = GpgME::Context::None) = 0;
+
+    /** Like exec but with an additional argument for EncryptionFlags for
+     * more flexibility. */
+    virtual GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+                                         const QByteArray &plainText,
+                                         const GpgME::Context::EncryptionFlags flags, QByteArray &cipherText) = 0;
 Q_SIGNALS:
     void result(const GpgME::EncryptionResult &result, const QByteArray &cipherText, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
 };
diff --git a/lang/qt/src/qgpgmeencryptjob.cpp b/lang/qt/src/qgpgmeencryptjob.cpp
index 8d0bfd4..82c8ed8 100644
--- a/lang/qt/src/qgpgmeencryptjob.cpp
+++ b/lang/qt/src/qgpgmeencryptjob.cpp
@@ -65,7 +65,7 @@ static QGpgMEEncryptJob::result_type encrypt(Context *ctx, QThread *thread,
         const std::vector<Key> &recipients,
         const std::weak_ptr<QIODevice> &plainText_,
         const std::weak_ptr<QIODevice> &cipherText_,
-        bool alwaysTrust,
+        const Context::EncryptionFlags eflags,
         bool outputIsBsse64Encoded)
 {
 
@@ -78,9 +78,6 @@ static QGpgMEEncryptJob::result_type encrypt(Context *ctx, QThread *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);
@@ -109,41 +106,54 @@ static QGpgMEEncryptJob::result_type encrypt(Context *ctx, QThread *thread,
 
 }
 
-static QGpgMEEncryptJob::result_type encrypt_qba(Context *ctx, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, bool outputIsBsse64Encoded)
+static QGpgMEEncryptJob::result_type encrypt_qba(Context *ctx, const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
 {
     const std::shared_ptr<QBuffer> buffer(new QBuffer);
     buffer->setData(plainText);
     if (!buffer->open(QIODevice::ReadOnly)) {
         assert(!"This should never happen: QBuffer::open() failed");
     }
-    return encrypt(ctx, 0, recipients, buffer, std::shared_ptr<QIODevice>(), alwaysTrust, outputIsBsse64Encoded);
+    return encrypt(ctx, 0, recipients, buffer, std::shared_ptr<QIODevice>(), eflags, outputIsBsse64Encoded);
 }
 
 Error QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
 {
-    run(std::bind(&encrypt_qba, std::placeholders::_1, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded));
+    run(std::bind(&encrypt_qba, std::placeholders::_1, recipients, plainText,
+                  alwaysTrust ? Context::AlwaysTrust : Context::None, mOutputIsBase64Encoded));
     return Error();
 }
 
-void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText,
+                             const std::shared_ptr<QIODevice> &cipherText, const Context::EncryptionFlags eflags)
 {
     run(std::bind(&encrypt,
                     std::placeholders::_1, std::placeholders::_2,
                     recipients,
                     std::placeholders::_3, std::placeholders::_4,
-                    alwaysTrust,
+                    eflags,
                     mOutputIsBase64Encoded),
         plainText, cipherText);
 }
 
-EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText,
+                                        const Context::EncryptionFlags eflags, QByteArray &cipherText)
 {
-    const result_type r = encrypt_qba(context(), recipients, plainText, alwaysTrust, mOutputIsBase64Encoded);
+    const result_type r = encrypt_qba(context(), recipients, plainText, eflags, mOutputIsBase64Encoded);
     cipherText = std::get<1>(r);
     resultHook(r);
     return mResult;
 }
 
+void QGpgMEEncryptJob::start(const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
+{
+    return start(recipients, plainText, cipherText, alwaysTrust ? Context::AlwaysTrust : Context::None);
+}
+
+EncryptionResult QGpgMEEncryptJob::exec(const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+    return exec(recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, cipherText);
+}
+
 void QGpgMEEncryptJob::resultHook(const result_type &tuple)
 {
     mResult = std::get<0>(tuple);
diff --git a/lang/qt/src/qgpgmeencryptjob.h b/lang/qt/src/qgpgmeencryptjob.h
index d35a41b..42c1c78 100644
--- a/lang/qt/src/qgpgmeencryptjob.h
+++ b/lang/qt/src/qgpgmeencryptjob.h
@@ -82,6 +82,16 @@ public:
     GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
                                  const QByteArray &plainText, bool alwaysTrust,
                                  QByteArray &cipherText) Q_DECL_OVERRIDE;
+    /* from EncryptJob */
+    void start(const std::vector<GpgME::Key> &recipients,
+               const std::shared_ptr<QIODevice> &plainText,
+               const std::shared_ptr<QIODevice> &cipherText,
+               const GpgME::Context::EncryptionFlags flags) Q_DECL_OVERRIDE;
+
+    /* from EncryptJob */
+    GpgME::EncryptionResult exec(const std::vector<GpgME::Key> &recipients,
+                                 const QByteArray &plainText, const GpgME::Context::EncryptionFlags flags,
+                                 QByteArray &cipherText) Q_DECL_OVERRIDE;
 
     /* from EncryptJob */
     void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
diff --git a/lang/qt/src/qgpgmesignencryptjob.cpp b/lang/qt/src/qgpgmesignencryptjob.cpp
index d19ab0f..d2e45b1 100644
--- a/lang/qt/src/qgpgmesignencryptjob.cpp
+++ b/lang/qt/src/qgpgmesignencryptjob.cpp
@@ -62,7 +62,9 @@ void QGpgMESignEncryptJob::setOutputIsBase64Encoded(bool on)
     mOutputIsBase64Encoded = on;
 }
 
-static QGpgMESignEncryptJob::result_type sign_encrypt(Context *ctx, QThread *thread, const std::vector<Key> &signers, const std::vector<Key> &recipients, const std::weak_ptr<QIODevice> &plainText_, const std::weak_ptr<QIODevice> &cipherText_, bool alwaysTrust, bool outputIsBsse64Encoded)
+static QGpgMESignEncryptJob::result_type sign_encrypt(Context *ctx, QThread *thread, const std::vector<Key> &signers,
+                                                      const std::vector<Key> &recipients, const std::weak_ptr<QIODevice> &plainText_,
+                                                      const std::weak_ptr<QIODevice> &cipherText_, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
 {
     const std::shared_ptr<QIODevice> &plainText = plainText_.lock();
     const std::shared_ptr<QIODevice> &cipherText = cipherText_.lock();
@@ -73,9 +75,6 @@ static QGpgMESignEncryptJob::result_type sign_encrypt(Context *ctx, QThread *thr
     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())
@@ -111,35 +110,48 @@ static QGpgMESignEncryptJob::result_type sign_encrypt(Context *ctx, QThread *thr
 
 }
 
-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)
+static QGpgMESignEncryptJob::result_type sign_encrypt_qba(Context *ctx, const std::vector<Key> &signers,
+                                                          const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, bool outputIsBsse64Encoded)
 {
     const std::shared_ptr<QBuffer> buffer(new QBuffer);
     buffer->setData(plainText);
     if (!buffer->open(QIODevice::ReadOnly)) {
         assert(!"This should never happen: QBuffer::open() failed");
     }
-    return sign_encrypt(ctx, 0, signers, recipients, buffer, std::shared_ptr<QIODevice>(), alwaysTrust, outputIsBsse64Encoded);
+    return sign_encrypt(ctx, 0, signers, recipients, buffer, std::shared_ptr<QIODevice>(), eflags, outputIsBsse64Encoded);
 }
 
 Error QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust)
 {
-    run(std::bind(&sign_encrypt_qba, std::placeholders::_1, signers, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded));
+    run(std::bind(&sign_encrypt_qba, std::placeholders::_1, signers, recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, mOutputIsBase64Encoded));
     return Error();
 }
 
+void QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients,
+                                 const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, const Context::EncryptionFlags eflags)
+{
+    run(std::bind(&sign_encrypt, std::placeholders::_1, std::placeholders::_2, signers, recipients, std::placeholders::_3, std::placeholders::_4, eflags, mOutputIsBase64Encoded), plainText, cipherText);
+}
+
 void QGpgMESignEncryptJob::start(const std::vector<Key> &signers, const std::vector<Key> &recipients, const std::shared_ptr<QIODevice> &plainText, const std::shared_ptr<QIODevice> &cipherText, bool alwaysTrust)
 {
-    run(std::bind(&sign_encrypt, std::placeholders::_1, std::placeholders::_2, signers, recipients, std::placeholders::_3, std::placeholders::_4, alwaysTrust, mOutputIsBase64Encoded), plainText, cipherText);
+    return start(signers, recipients, plainText, cipherText, alwaysTrust ? Context::AlwaysTrust : Context::None);
 }
 
-std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, const Context::EncryptionFlags eflags, QByteArray &cipherText)
 {
-    const result_type r = sign_encrypt_qba(context(), signers, recipients, plainText, alwaysTrust, mOutputIsBase64Encoded);
+    const result_type r = sign_encrypt_qba(context(), signers, recipients, plainText, eflags, mOutputIsBase64Encoded);
     cipherText = std::get<2>(r);
     resultHook(r);
     return mResult;
 }
 
+std::pair<SigningResult, EncryptionResult> QGpgMESignEncryptJob::exec(const std::vector<Key> &signers, const std::vector<Key> &recipients, const QByteArray &plainText, bool alwaysTrust, QByteArray &cipherText)
+{
+    return exec(signers, recipients, plainText, alwaysTrust ? Context::AlwaysTrust : Context::None, cipherText);
+}
+
+
 #if 0
 
 TODO port?
diff --git a/lang/qt/src/qgpgmesignencryptjob.h b/lang/qt/src/qgpgmesignencryptjob.h
index 49177d3..e76c245 100644
--- a/lang/qt/src/qgpgmesignencryptjob.h
+++ b/lang/qt/src/qgpgmesignencryptjob.h
@@ -87,12 +87,24 @@ public:
                const std::shared_ptr<QIODevice> &cipherText,
                bool alwaysTrust) Q_DECL_OVERRIDE;
 
+    void start(const std::vector<GpgME::Key> &signers,
+               const std::vector<GpgME::Key> &recipients,
+               const std::shared_ptr<QIODevice> &plainText,
+               const std::shared_ptr<QIODevice> &cipherText,
+               const GpgME::Context::EncryptionFlags flags) Q_DECL_OVERRIDE;
+
     std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
     exec(const std::vector<GpgME::Key> &signers,
          const std::vector<GpgME::Key> &recipients,
          const QByteArray &plainText, bool alwaysTrust,
          QByteArray &cipherText) Q_DECL_OVERRIDE;
 
+    std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+    exec(const std::vector<GpgME::Key> &signers,
+         const std::vector<GpgME::Key> &recipients,
+         const QByteArray &plainText, const GpgME::Context::EncryptionFlags flags,
+         QByteArray &cipherText) Q_DECL_OVERRIDE;
+
     /* from SignEncryptJob */
     void setOutputIsBase64Encoded(bool on) Q_DECL_OVERRIDE;
 
diff --git a/lang/qt/src/signencryptjob.h b/lang/qt/src/signencryptjob.h
index 4818d2a..b0aafe3 100644
--- a/lang/qt/src/signencryptjob.h
+++ b/lang/qt/src/signencryptjob.h
@@ -38,8 +38,10 @@
 
 #ifdef BUILDING_QGPGME
 # include "global.h"
+# include "context.h"
 #else
 # include <gpgme++/global.h>
+# include <gpgme++/context.h>
 #endif
 
 #include <memory>
@@ -123,6 +125,21 @@ public:
     */
     virtual void setOutputIsBase64Encoded(bool) = 0;
 
+    /** Like start but with an additional argument for EncryptionFlags for
+     * more flexibility. */
+    virtual void start(const std::vector<GpgME::Key> &signers,
+                       const std::vector<GpgME::Key> &recipients,
+                       const std::shared_ptr<QIODevice> &plainText,
+                       const std::shared_ptr<QIODevice> &cipherText = std::shared_ptr<QIODevice>(),
+                       const GpgME::Context::EncryptionFlags flags = GpgME::Context::None) = 0;
+
+    /** Like exec but with an additional argument for EncryptionFlags for
+     * more flexibility. */
+    virtual std::pair<GpgME::SigningResult, GpgME::EncryptionResult>
+    exec(const std::vector<GpgME::Key> &signers,
+         const std::vector<GpgME::Key> &recipients,
+         const QByteArray &plainText,
+         const GpgME::Context::EncryptionFlags flags, QByteArray &cipherText) = 0;
 Q_SIGNALS:
     void result(const GpgME::SigningResult &signingresult,
                 const GpgME::EncryptionResult &encryptionresult,

commit 17372393798ea5e2d6838f3dd1e001dd4a66c941
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 9 13:07:30 2016 +0200

    Cpp: Add support for all EncryptionFlags
    
    * lang/cpp/src/context.h (EncryptionFlags): Extend.
    * lang/cpp/src/context.cpp (encryptflags2encryptflags): Ditto.

diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp
index 814e5a8..d63573f 100644
--- a/lang/cpp/src/context.cpp
+++ b/lang/cpp/src/context.cpp
@@ -1094,6 +1094,18 @@ static gpgme_encrypt_flags_t encryptflags2encryptflags(Context::EncryptionFlags
     if (flags & Context::NoEncryptTo) {
         result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
     }
+    if (flags & Context::Prepare) {
+        result |= GPGME_ENCRYPT_PREPARE;
+    }
+    if (flags & Context::ExpectSign) {
+        result |= GPGME_ENCRYPT_EXPECT_SIGN;
+    }
+    if (flags & Context::NoCompress) {
+        result |= GPGME_ENCRYPT_NO_COMPRESS;
+    }
+    if (flags & Context::Symmetric) {
+        result |= GPGME_ENCRYPT_SYMMETRIC;
+    }
     return static_cast<gpgme_encrypt_flags_t>(result);
 }
 
@@ -1395,6 +1407,11 @@ std::ostream &operator<<(std::ostream &os, Context::EncryptionFlags flags)
     os << "GpgME::Context::EncryptionFlags(";
 #define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
     CHECK(AlwaysTrust);
+    CHECK(NoEncryptTo);
+    CHECK(Prepare);
+    CHECK(ExpectSign);
+    CHECK(NoCompress);
+    CHECK(Symmetric);
 #undef CHECK
     return os << ')';
 }
diff --git a/lang/cpp/src/context.h b/lang/cpp/src/context.h
index c9c2af7..c7c0ecb 100644
--- a/lang/cpp/src/context.h
+++ b/lang/cpp/src/context.h
@@ -292,7 +292,15 @@ public:
     // Encryption
     //
 
-    enum EncryptionFlags { None = 0, AlwaysTrust = 1, NoEncryptTo = 2 };
+    enum EncryptionFlags {
+        None = 0,
+        AlwaysTrust = 1,
+        NoEncryptTo = 2,
+        Prepare = 4,
+        ExpectSign = 8,
+        NoCompress = 16,
+        Symmetric = 32
+    };
     EncryptionResult encrypt(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);
     GpgME::Error encryptSymmetrically(const Data &plainText, Data &cipherText);
     GpgME::Error startEncryption(const std::vector<Key> &recipients, const Data &plainText, Data &cipherText, EncryptionFlags flags);

commit bf776ce94cf454f1b3f1645b1cde09cd1c54324b
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 9 12:56:01 2016 +0200

    Cpp: Fix simple symmetric encryption
    
    * lang/cpp/src/context.cpp (Context::encrypt): If no recipients
    are provided encrypt with NULL and not an empty array.
    
    --
    Sending an empty array leads to an invalid argument error.

diff --git a/lang/cpp/src/context.cpp b/lang/cpp/src/context.cpp
index 20d827e..814e5a8 100644
--- a/lang/cpp/src/context.cpp
+++ b/lang/cpp/src/context.cpp
@@ -1113,7 +1113,8 @@ EncryptionResult Context::encrypt(const std::vector<Key> &recipients, const Data
         }
     }
     *keys_it++ = 0;
-    d->lasterr = gpgme_op_encrypt(d->ctx, keys, encryptflags2encryptflags(flags),
+    d->lasterr = gpgme_op_encrypt(d->ctx, recipients.empty() ? nullptr : keys,
+                                  encryptflags2encryptflags(flags),
                                   pdp ? pdp->data : 0, cdp ? cdp->data : 0);
     delete[] keys;
     return EncryptionResult(d->ctx, Error(d->lasterr));

commit 3d2f027d0f40e7ec4ab48cee89ff0ee10b423566
Author: Andre Heinecke <aheinecke at intevation.de>
Date:   Tue Aug 9 11:40:29 2016 +0200

    core: Add support for mixed symmetric and asym enc
    
    * src/gpgme.h.in (gpgme_encrypt_flags_t): New flag
    GPGME_ENCRYPT_SYMMETRIC.
    * src/engine-gpg.c (gpg_encrypt): Also add --symmetric if the flag
    is given.
    * NEWS: Mention new flag.
    * tests/run-encrypt.c (show_usage): Extend for --symmetric.
    (main): Handle --symmetric.
    (main): Set passphrase_cb in loopback mode.
    (main): Fix encrypt call if no recipients are given.
    * tests/gpg/t-encrypt-mixed.c: New.
    * tests/gpg/Makefile.am (c_tests): Add new test.
    * doc/gpgme.texi: Document new flag.

diff --git a/NEWS b/NEWS
index 09d0a1c..71c18a8 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,7 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_DATA_TYPE_PGP_ENCRYPTED  NEW.
  GPGME_DATA_TYPE_PGP_SIGNATURE  NEW.
  GPGME_DATA_ENCODING_MIME       NEW.
+ GPGME_ENCRYPT_SYMMETRIC        NEW.
 
 
 Noteworthy changes in version 1.6.0 (2015-08-26) [C25/A14/R0]
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index 68f85ec..907099a 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -5398,6 +5398,12 @@ protocol to prepare an encryption (i.e. sending the
 @code{GPGME_ENCRYPT_EXPECT_SIGN} symbol the UI Server is advised to
 also expect a sign command.
 
+ at item GPGME_ENCRYPT_SYMMETRIC
+The @code{GPGME_ENCRYPT_SYMMETRIC} symbol specifies that the
+output should be additionally encrypted symmetically even
+if recipients are provided. This feature is only supported for
+for the OpenPGP crypto engine.
+
 @end table
 
 If @code{GPG_ERR_UNUSABLE_PUBKEY} is returned, some recipients in
diff --git a/src/engine-gpg.c b/src/engine-gpg.c
index 942711f..ae78d9d 100644
--- a/src/engine-gpg.c
+++ b/src/engine-gpg.c
@@ -1718,9 +1718,12 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
 {
   engine_gpg_t gpg = engine;
   gpgme_error_t err;
-  int symmetric = !recp;
 
-  err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
+  if (recp)
+    err = add_arg (gpg, "--encrypt");
+
+  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || !recp))
+    err = add_arg (gpg, "--symmetric");
 
   if (!err && use_armor)
     err = add_arg (gpg, "--armor");
@@ -1732,7 +1735,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
       && have_gpg_version (gpg, "2.1.14"))
     err = add_arg (gpg, "--mimemode");
 
-  if (!symmetric)
+  if (recp)
     {
       /* If we know that all recipients are valid (full or ultimate trust)
 	 we can suppress further checks.  */
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index c05686d..56d15f4 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -1392,7 +1392,8 @@ typedef enum
     GPGME_ENCRYPT_NO_ENCRYPT_TO = 2,
     GPGME_ENCRYPT_PREPARE = 4,
     GPGME_ENCRYPT_EXPECT_SIGN = 8,
-    GPGME_ENCRYPT_NO_COMPRESS = 16
+    GPGME_ENCRYPT_NO_COMPRESS = 16,
+    GPGME_ENCRYPT_SYMMETRIC = 32
   }
 gpgme_encrypt_flags_t;
 
diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am
index 107397b..e1c033b 100644
--- a/tests/gpg/Makefile.am
+++ b/tests/gpg/Makefile.am
@@ -38,7 +38,7 @@ c_tests = \
         t-encrypt t-encrypt-sym t-encrypt-sign t-sign t-signers		\
 	t-decrypt t-verify t-decrypt-verify t-sig-notation t-export	\
 	t-import t-trustlist t-edit t-keylist t-keylist-sig t-wait	\
-	t-encrypt-large t-file-name t-gpgconf $(tests_unix)
+	t-encrypt-large t-file-name t-gpgconf t-encrypt-mixed $(tests_unix)
 
 TESTS = initial.test $(c_tests) final.test
 
diff --git a/tests/gpg/t-encrypt-mixed.c b/tests/gpg/t-encrypt-mixed.c
new file mode 100644
index 0000000..28d8aa3
--- /dev/null
+++ b/tests/gpg/t-encrypt-mixed.c
@@ -0,0 +1,126 @@
+/* t-encrypt-mixed.c - Regression test.
+   Copyright (C) 2016 Intevation GmbH
+
+   This file is part of GPGME.
+
+   GPGME is free software; you can redistribute it and/or modify it
+   under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   GPGME is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <gpgme.h>
+
+#include "t-support.h"
+
+/* Tests mixed symmetric and asymetric decryption. Verifies
+   that an encrypted message can be decrypted without the
+   secret key but that the recipient is also set correctly. */
+int
+main (int argc, char *argv[])
+{
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_data_t in, out;
+  gpgme_key_t key[2] = { NULL, NULL };
+  gpgme_encrypt_result_t result;
+  gpgme_decrypt_result_t dec_result;
+  gpgme_recipient_t recipient;
+  const char *text = "Hallo Leute\n";
+  char *text2;
+  size_t len;
+
+  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+
+  err = gpgme_new (&ctx);
+  fail_if_err (err);
+  gpgme_set_armor (ctx, 1);
+
+  err = gpgme_data_new_from_mem (&in, text, strlen (text), 0);
+  fail_if_err (err);
+
+  err = gpgme_data_new (&out);
+  fail_if_err (err);
+
+  /* A recipient for which we don't have a secret key */
+  err = gpgme_get_key (ctx, "D695676BDCEDCC2CDD6152BCFE180B1DA9E3B0B2",
+                       &key[0], 0);
+  fail_if_err (err);
+
+  err = gpgme_op_encrypt (ctx, key,
+                          GPGME_ENCRYPT_ALWAYS_TRUST | GPGME_ENCRYPT_SYMMETRIC,
+                          in, out);
+  fail_if_err (err);
+  result = gpgme_op_encrypt_result (ctx);
+  if (result->invalid_recipients)
+    {
+      fprintf (stderr, "Invalid recipient encountered: %s\n",
+               result->invalid_recipients->fpr);
+      exit (1);
+    }
+
+  print_data (out);
+
+  /* Now try to decrypt */
+  gpgme_data_seek (out, 0, SEEK_SET);
+
+  gpgme_data_release (in);
+  err = gpgme_data_new (&in);
+  fail_if_err (err);
+
+  err = gpgme_op_decrypt (ctx, out, in);
+  fail_if_err (err);
+
+  fputs ("Begin Result Decryption:\n", stdout);
+  print_data (in);
+  fputs ("End Result.\n", stdout);
+
+  dec_result = gpgme_op_decrypt_result (ctx);
+  if (dec_result->unsupported_algorithm || dec_result->wrong_key_usage)
+    {
+      fprintf (stderr, "%s:%d: Decryption failed\n", __FILE__, __LINE__);
+      exit (1);
+    }
+
+  text2 = gpgme_data_release_and_get_mem (in, &len);
+  if (strncmp (text, text2, len))
+    {
+      fprintf (stderr, "%s:%d: Wrong plaintext\n", __FILE__, __LINE__);
+      exit (1);
+    }
+
+  recipient = dec_result->recipients;
+  if (!recipient || recipient->next)
+    {
+      fprintf (stderr, "%s:%d: Invalid recipients \n", __FILE__, __LINE__);
+      exit (1);
+    }
+
+  if (strncmp (recipient->keyid, "5381EA4EE29BA37F", 16))
+    {
+      fprintf (stderr, "%s:%d: Not encrypted to recipient's subkey \n", __FILE__, __LINE__);
+      exit (1);
+    }
+
+  gpgme_key_unref (key[0]);
+  gpgme_data_release (out);
+  gpgme_release (ctx);
+  return 0;
+}
diff --git a/tests/run-encrypt.c b/tests/run-encrypt.c
index a00f028..210f88a 100644
--- a/tests/run-encrypt.c
+++ b/tests/run-encrypt.c
@@ -70,6 +70,7 @@ show_usage (int ex)
          "  --uiserver       use the UI server\n"
          "  --loopback       use a loopback pinentry\n"
          "  --key NAME       encrypt to key NAME\n"
+         "  --symmetric      encrypt symmetric (OpenPGP only)\n"
          , stderr);
   exit (ex);
 }
@@ -91,6 +92,7 @@ main (int argc, char **argv)
   gpgme_key_t keys[10+1];
   int keycount = 0;
   int i;
+  gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
 
   if (argc)
     { argc--; argv++; }
@@ -148,6 +150,11 @@ main (int argc, char **argv)
           use_loopback = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--symmetric"))
+        {
+          flags |= GPGME_ENCRYPT_SYMMETRIC;
+          argc--; argv++;
+        }
       else if (!strncmp (*argv, "--", 2))
         show_usage (1);
 
@@ -174,7 +181,10 @@ main (int argc, char **argv)
   if (print_status)
     gpgme_set_status_cb (ctx, status_cb, NULL);
   if (use_loopback)
-    gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+    {
+      gpgme_set_pinentry_mode (ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+      gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
+    }
 
   for (i=0; i < keycount; i++)
     {
@@ -194,7 +204,7 @@ main (int argc, char **argv)
   err = gpgme_data_new (&out);
   fail_if_err (err);
 
-  err = gpgme_op_encrypt (ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  err = gpgme_op_encrypt (ctx, keycount ? keys : NULL, flags, in, out);
   result = gpgme_op_encrypt_result (ctx);
   if (result)
     print_result (result);

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                               |   1 +
 doc/gpgme.texi                                     |   6 +
 lang/cpp/src/context.cpp                           |  20 ++-
 lang/cpp/src/context.h                             |  10 +-
 lang/qt/src/encryptjob.h                           |  19 +-
 lang/qt/src/qgpgmeencryptjob.cpp                   |  32 ++--
 lang/qt/src/qgpgmeencryptjob.h                     |  10 ++
 lang/qt/src/qgpgmesignencryptjob.cpp               |  32 ++--
 lang/qt/src/qgpgmesignencryptjob.h                 |  12 ++
 lang/qt/src/signencryptjob.h                       |  17 ++
 lang/qt/tests/Makefile.am                          |  22 ++-
 lang/qt/tests/t-encrypt.cpp                        | 194 +++++++++++++++++++++
 lang/qt/tests/t-keylist.cpp                        |  17 +-
 lang/qt/tests/t-keylocate.cpp                      |  14 +-
 lang/qt/tests/t-ownertrust.cpp                     |  15 +-
 .../{src/qgpgmedeletejob.h => tests/t-support.cpp} |  56 +++---
 lang/qt/tests/t-support.h                          |  19 +-
 lang/qt/tests/t-tofuinfo.cpp                       |   4 +-
 src/engine-gpg.c                                   |   9 +-
 src/gpgme.h.in                                     |   3 +-
 tests/gpg/Makefile.am                              |   2 +-
 tests/gpg/t-encrypt-mixed.c                        | 126 +++++++++++++
 tests/run-encrypt.c                                |  14 +-
 23 files changed, 545 insertions(+), 109 deletions(-)
 create mode 100644 lang/qt/tests/t-encrypt.cpp
 copy lang/qt/{src/qgpgmedeletejob.h => tests/t-support.cpp} (66%)
 create mode 100644 tests/gpg/t-encrypt-mixed.c


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list