qt: Add WKSPublishJob
authorAndre Heinecke <aheinecke@intevation.de>
Thu, 25 Aug 2016 12:29:41 +0000 (14:29 +0200)
committerAndre Heinecke <aheinecke@intevation.de>
Thu, 25 Aug 2016 12:29:41 +0000 (14:29 +0200)
* lang/qt/src/Makefile.am: Add new files.
* lang/qt/src/job.cpp: Include moc / subclass stub.
* lang/qt/src/protocol.h: Add virtual for new job.
* lang/qt/src/protocol_p.h: Add job.
* lang/qt/src/wkspublishjob.h: Interface for WKSPublishJob.
* lang/qt/src/qgpgmewkspublishjob.cpp,
lang/qt/src/qgpgmewkspublishjob.h: New.

--
The Job was originally intended to be used with a SpawnEngine
Context but QProcess was a better fit for the job.

Usage is similar to the client tool. check, create, recieve.

lang/qt/src/Makefile.am
lang/qt/src/job.cpp
lang/qt/src/protocol.h
lang/qt/src/protocol_p.h
lang/qt/src/qgpgmewkspublishjob.cpp [new file with mode: 0644]
lang/qt/src/qgpgmewkspublishjob.h [new file with mode: 0644]
lang/qt/src/wkspublishjob.h [new file with mode: 0644]

index 840557e..8f6d773 100644 (file)
@@ -34,7 +34,7 @@ qgpgme_sources = \
     qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \
     qgpgmeverifyopaquejob.cpp threadedjobmixin.cpp \
     qgpgmekeyformailboxjob.cpp gpgme_backend_debug.cpp \
-    defaultkeygenerationjob.cpp
+    defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp
 
 # If you add one here make sure that you also add one in camelcase
 qgpgme_headers= \
@@ -68,7 +68,8 @@ qgpgme_headers= \
     keylistjob.h \
     listallkeysjob.h \
     verifydetachedjob.h \
-    defaultkeygenerationjob.h
+    defaultkeygenerationjob.h \
+    wkspublishjob.h
 
 camelcase_headers= \
     AddUserIDJob \
@@ -100,7 +101,8 @@ camelcase_headers= \
     ListAllKeysJob \
     VerifyDetachedJob \
     KeyForMailboxJob \
-    DefaultKeyGenerationJob
+    DefaultKeyGenerationJob \
+    WKSPublishJob
 
 private_qgpgme_headers = \
     qgpgme_export.h \
@@ -130,6 +132,7 @@ private_qgpgme_headers = \
     qgpgmeverifydetachedjob.h \
     qgpgmeverifyopaquejob.h \
     qgpgmekeyformailboxjob.h \
+    qgpgmewkspublishjob.h \
     specialjob.h \
     threadedjobmixin.h
 
@@ -175,6 +178,7 @@ qgpgme_moc_sources = \
     qgpgmesignkeyjob.moc \
     qgpgmeverifydetachedjob.moc \
     qgpgmeverifyopaquejob.moc \
+    qgpgmewkspublishjob.moc \
     refreshkeysjob.moc \
     signencryptjob.moc \
     signjob.moc \
@@ -183,6 +187,7 @@ qgpgme_moc_sources = \
     verifydetachedjob.moc \
     verifyopaquejob.moc \
     keyformailboxjob.moc \
+    wkspublishjob.moc \
     qgpgmekeyformailboxjob.moc \
     defaultkeygenerationjob.moc
 
index 8e50647..6b355a0 100644 (file)
@@ -56,6 +56,7 @@
 #include "adduseridjob.h"
 #include "specialjob.h"
 #include "keyformailboxjob.h"
+#include "wkspublishjob.h"
 
 #include <QCoreApplication>
 #include <QDebug>
@@ -122,6 +123,7 @@ make_job_subclass(RefreshKeysJob)
 make_job_subclass(AddUserIDJob)
 make_job_subclass(SpecialJob)
 make_job_subclass(KeyForMailboxJob)
+make_job_subclass(WKSPublishJob)
 
 #undef make_job_subclass
 
@@ -151,3 +153,4 @@ make_job_subclass(KeyForMailboxJob)
 #include "adduseridjob.moc"
 #include "specialjob.moc"
 #include "keyformailboxjob.moc"
+#include "wkspublishjob.moc"
index 23b9d93..b2dee1d 100644 (file)
@@ -63,6 +63,7 @@ class ChangePasswdJob;
 class AddUserIDJob;
 class SpecialJob;
 class KeyForMailboxJob;
+class WKSPublishJob;
 
 /** The main entry point for QGpgME Comes in OpenPGP and SMIME(CMS) flavors.
  *
@@ -148,6 +149,9 @@ public:
     virtual KeyListJob *locateKeysJob() const = 0;
     /** Find the best key to use for a mailbox. */
     virtual KeyForMailboxJob *keyForMailboxJob() const = 0;
+
+    /** A Job for interacting with gnupg's wks tools. */
+    virtual WKSPublishJob *wksPublishJob() const = 0;
 };
 
 /** Obtain a reference to the OpenPGP Protocol.
index afb4f9c..2ce4182 100644 (file)
@@ -57,6 +57,7 @@
 #include "qgpgmechangepasswdjob.h"
 #include "qgpgmeadduseridjob.h"
 #include "qgpgmekeyformailboxjob.h"
+#include "qgpgmewkspublishjob.h"
 
 namespace
 {
@@ -387,6 +388,18 @@ public:
         }
         return new QGpgME::QGpgMEKeyForMailboxJob(context);
     }
+
+    QGpgME::WKSPublishJob *wksPublishJob() const Q_DECL_OVERRIDE
+    {
+        if (mProtocol != GpgME::OpenPGP) {
+            return Q_NULLPTR;
+        }
+        auto context = GpgME::Context::createForEngine(GpgME::SpawnEngine);
+        if (!context) {
+            return Q_NULLPTR;
+        }
+        return new QGpgME::QGpgMEWKSPublishJob(context.release());
+    }
 };
 
 }
diff --git a/lang/qt/src/qgpgmewkspublishjob.cpp b/lang/qt/src/qgpgmewkspublishjob.cpp
new file mode 100644 (file)
index 0000000..8f97cb5
--- /dev/null
@@ -0,0 +1,189 @@
+/* wkspublishjob.cpp
+
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#include "qgpgmewkspublishjob.h"
+
+#include "context.h"
+#include "key.h"
+#include "util.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <QProcess>
+
+/* Timeout for the WKS Processes will be 5 Minutes as
+ * they can involve pinentry questions. */
+#define TIMEOUT_VALUE (5*60*1000)
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEWKSPublishJob::QGpgMEWKSPublishJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEWKSPublishJob::~QGpgMEWKSPublishJob() {}
+
+static QString getWKSClient()
+{
+    auto libexecdir = QString::fromLocal8Bit(dirInfo("libexecdir"));
+    if (libexecdir.isEmpty()) {
+        return QString();
+    }
+
+    const QFileInfo fi(QDir(libexecdir).absoluteFilePath(QStringLiteral("gpg-wks-client")));
+    if (fi.exists() && fi.isExecutable()) {
+        return fi.absoluteFilePath();
+    }
+    return QString();
+}
+
+static QGpgMEWKSPublishJob::result_type check_worker(const QString &mail)
+{
+    if (mail.isEmpty()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    const auto wksPath = getWKSClient();
+    if (wksPath.isEmpty()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    /* QProcess instead of engine_spawn because engine_spawn does not communicate
+     * the return value of the process and we are in qt anyway. */
+    QProcess proc;
+    proc.setProgram(wksPath);
+    proc.setArguments(QStringList() << QStringLiteral("--supported") << mail);
+    proc.start();
+    if (!proc.waitForStarted()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+    if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+        return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+    if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+        return std::make_tuple (Error(), QByteArray(), QByteArray(), QString(), Error());
+    }
+    return std::make_tuple (Error(make_error(GPG_ERR_NOT_ENABLED)),
+                            QByteArray(), QByteArray(), QString(), Error());
+}
+
+static QGpgMEWKSPublishJob::result_type create_worker(const char *fpr, const QString &mail)
+{
+    if (mail.isEmpty() || !fpr) {
+        return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    const auto wksPath = getWKSClient();
+    if (wksPath.isEmpty()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    QProcess proc;
+    proc.setProgram(wksPath);
+    proc.setArguments(QStringList() << QStringLiteral("--create")
+                                    << QLatin1String(fpr)
+                                    << mail);
+    proc.start();
+    if (!proc.waitForStarted()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+        return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+    if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+        return std::make_tuple (Error(), proc.readAllStandardOutput(),
+                                proc.readAllStandardError(), QString(), Error());
+    }
+    return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
+                            proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
+}
+
+static QGpgMEWKSPublishJob::result_type recieve_worker(const QByteArray &response)
+{
+    if (response.isEmpty()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_INV_ARG)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    const auto wksPath = getWKSClient();
+    if (wksPath.isEmpty()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+
+    QProcess proc;
+    proc.setProgram(wksPath);
+    proc.setArguments(QStringList() << QStringLiteral("--receive"));
+    proc.start();
+    if (!proc.waitForStarted()) {
+        return std::make_tuple (Error(make_error(GPG_ERR_NOT_SUPPORTED)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+    proc.write(response);
+    proc.closeWriteChannel();
+    if (!proc.waitForFinished(TIMEOUT_VALUE)) {
+        return std::make_tuple (Error(make_error(GPG_ERR_TIMEOUT)),
+                                QByteArray(), QByteArray(), QString(), Error());
+    }
+    if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0) {
+        return std::make_tuple (Error(), proc.readAllStandardOutput(),
+                                proc.readAllStandardError(), QString(), Error());
+    }
+    return std::make_tuple (Error(make_error(GPG_ERR_GENERAL)),
+                            proc.readAllStandardOutput(), proc.readAllStandardError(), QString(), Error());
+}
+
+void QGpgMEWKSPublishJob::startCheck(const QString &mailbox)
+{
+    run(std::bind(&check_worker, mailbox));
+}
+
+void QGpgMEWKSPublishJob::startCreate(const char *fpr, const QString &mailbox) {
+    run(std::bind(&create_worker, fpr, mailbox));
+}
+
+void QGpgMEWKSPublishJob::startRecieve(const QByteArray &response)
+{
+    run(std::bind(&recieve_worker, response));
+}
+
+#include "qgpgmewkspublishjob.moc"
diff --git a/lang/qt/src/qgpgmewkspublishjob.h b/lang/qt/src/qgpgmewkspublishjob.h
new file mode 100644 (file)
index 0000000..1a31149
--- /dev/null
@@ -0,0 +1,70 @@
+/* qgpgmewkspublishjob.h
+
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+#ifndef QGPGME_QGPGMEWKSPUBLISHJOB_H
+#define QGPGME_QGPGMEWKSPUBLISHJOB_H
+
+#include "wkspublishjob.h"
+
+#include "threadedjobmixin.h"
+namespace GpgME
+{
+    class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+/**
+ * Handles Web Key Service Publishing. Needs WKS tools installed and
+ * server support.
+ */
+class QGpgMEWKSPublishJob
+#ifdef Q_MOC_RUN
+    : public WKSPublishJob
+#else
+    : public _detail::ThreadedJobMixin<WKSPublishJob, std::tuple<GpgME::Error, QByteArray, QByteArray, QString, GpgME::Error> >
+#endif
+{
+    Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+    void slotFinished();
+#endif
+public:
+    explicit QGpgMEWKSPublishJob(GpgME::Context *context);
+    ~QGpgMEWKSPublishJob();
+
+    void startCheck(const QString &mailbox) Q_DECL_OVERRIDE;
+    void startCreate(const char *fpr, const QString &mailbox) Q_DECL_OVERRIDE;
+    void startRecieve(const QByteArray &response) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif
diff --git a/lang/qt/src/wkspublishjob.h b/lang/qt/src/wkspublishjob.h
new file mode 100644 (file)
index 0000000..782112f
--- /dev/null
@@ -0,0 +1,101 @@
+/* wkspublishjob.h
+
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+#ifndef QGPGME_WKSPUBLISHJOB_H
+#define QGPGME_WKSPUBLISHJOB_H
+
+#include "job.h"
+
+#include "qgpgme_export.h"
+
+namespace GpgME
+{
+    class Key;
+} // namespace GpgME
+
+namespace QGpgME {
+
+/**
+ * Handles Web Key Service Publishing. Needs WKS tools installed and
+ * server support.
+ *
+ * Remember that after a result is emited the job is auto deleted
+ * so you can only use it for a single action.
+ */
+class QGPGME_EXPORT WKSPublishJob: public Job
+{
+    Q_OBJECT
+protected:
+    explicit WKSPublishJob(QObject *parent);
+public:
+    ~WKSPublishJob();
+
+
+    /** Start a check if WKS Publishing is supported. As this involves
+     * an HTTP Query it might take a while. Returns GPG_ERR_NOT_SUPPORED
+     * result if GnuPG is too old or the required tools are not installed.
+     *
+     * The error GPG_ERR_NOT_ENABLED indicates that wks-tools failed to
+     * detect a working wks service for this.
+     *
+     * @param the mailbox to check for.
+     **/
+    virtual void startCheck(const QString &mailbox) = 0;
+
+    /** Create a publish request.
+     * The returned Data from the result will contain
+     * the full Mail as returned by gpg-wks-client --create
+     *
+     * @param fpr the fingerprint of the key to create the request for.
+     * @param mailbox A simple mail address without a Name.
+     */
+    virtual void startCreate(const char *fpr, const QString &mailbox) = 0;
+
+    /** Handle a submisson response. The returned Data will contain
+     * the full Mail as returned by gpg-wks-client --create
+     *
+     * @param response The response of the server.
+     **/
+    virtual void startRecieve(const QByteArray &response) = 0;
+
+Q_SIGNALS:
+    /* Result of the operation returned Data and returned Error are
+     * the results from gpg-wks-client's stdout or stderr respectively.
+     *
+     * As usual auditLogAsHtml and auditLogError can be ignored.
+     **/
+    void result(const GpgME::Error &error, const QByteArray &returnedData,
+                const QByteArray &returnedError,
+                const QString &auditLogAsHtml = QString(),
+                const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+
+#endif