Qt: Add KeyForMailboxJob
authorAndre Heinecke <aheinecke@intevation.de>
Thu, 11 Aug 2016 15:22:35 +0000 (17:22 +0200)
committerAndre Heinecke <aheinecke@intevation.de>
Thu, 11 Aug 2016 16:00:14 +0000 (18:00 +0200)
* lang/qt/src/job.cpp: Include moc and make subclass.
* lang/qt/src/keyformailboxjob.h,
lang/qt/src/qgpgmekeyformailboxjob.cpp,
lang/qt/src/qgpgmekeyformailboxjob.h: New.
* lang/qt/tests/run-keyformailboxjob.cpp: New manual test.
* lang/qt/tests/Makefile.am: Add run-keyformailboxjob.
* lang/qt/src/Makefile.am: Update accordingly.
* lang/qt/src/protocol.h, lang/qt/src/protocol_p.h: Add
keyformailboxjob.

--
The KeyForMailboxjob can be used to determine the best key to
use to encrypt something to a given mail address.

lang/qt/src/Makefile.am
lang/qt/src/job.cpp
lang/qt/src/keyformailboxjob.h [new file with mode: 0644]
lang/qt/src/protocol.h
lang/qt/src/protocol_p.h
lang/qt/src/qgpgmekeyformailboxjob.cpp [new file with mode: 0644]
lang/qt/src/qgpgmekeyformailboxjob.h [new file with mode: 0644]
lang/qt/tests/Makefile.am
lang/qt/tests/run-keyformailboxjob.cpp [new file with mode: 0644]

index ae316ba..59d8abc 100644 (file)
@@ -33,7 +33,7 @@ qgpgme_sources = \
     qgpgmesecretkeyexportjob.cpp qgpgmesignencryptjob.cpp \
     qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \
     qgpgmeverifyopaquejob.cpp threadedjobmixin.cpp \
-    gpgme_backend_debug.cpp
+    qgpgmekeyformailboxjob.cpp gpgme_backend_debug.cpp
 
 # If you add one here make sure that you also add one in camelcase
 qgpgme_headers= \
@@ -49,6 +49,7 @@ qgpgme_headers= \
     exportjob.h \
     hierarchicalkeylistjob.h \
     job.h \
+    keyformailboxjob.h \
     multideletejob.h \
     protocol.h \
     qgpgme_export.h \
@@ -95,7 +96,8 @@ camelcase_headers= \
     KeyGenerationJob \
     KeyListJob \
     ListAllKeysJob \
-    VerifyDetachedJob
+    VerifyDetachedJob \
+    KeyForMailboxJob
 
 private_qgpgme_headers = \
     qgpgme_export.h \
@@ -124,6 +126,7 @@ private_qgpgme_headers = \
     qgpgmesignkeyjob.h \
     qgpgmeverifydetachedjob.h \
     qgpgmeverifyopaquejob.h \
+    qgpgmekeyformailboxjob.h \
     specialjob.h \
     threadedjobmixin.h
 
@@ -175,7 +178,9 @@ qgpgme_moc_sources = \
     signkeyjob.moc \
     specialjob.moc \
     verifydetachedjob.moc \
-    verifyopaquejob.moc
+    verifyopaquejob.moc \
+    keyformailboxjob.moc \
+    qgpgmekeyformailboxjob.moc
 
 qgpgmeincludedir = $(includedir)/qgpgme
 qgpgmeinclude_HEADERS = $(qgpgme_headers)
index 7ca1df9..8e50647 100644 (file)
@@ -55,6 +55,7 @@
 #include "refreshkeysjob.h"
 #include "adduseridjob.h"
 #include "specialjob.h"
+#include "keyformailboxjob.h"
 
 #include <QCoreApplication>
 #include <QDebug>
@@ -120,6 +121,7 @@ make_job_subclass(DeleteJob)
 make_job_subclass(RefreshKeysJob)
 make_job_subclass(AddUserIDJob)
 make_job_subclass(SpecialJob)
+make_job_subclass(KeyForMailboxJob)
 
 #undef make_job_subclass
 
@@ -148,3 +150,4 @@ make_job_subclass(SpecialJob)
 #include "refreshkeysjob.moc"
 #include "adduseridjob.moc"
 #include "specialjob.moc"
+#include "keyformailboxjob.moc"
diff --git a/lang/qt/src/keyformailboxjob.h b/lang/qt/src/keyformailboxjob.h
new file mode 100644 (file)
index 0000000..9e76df5
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+    keyformailboxjob.h
+
+    This file is part of qgpgme, the Qt API binding for gpgme
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+#ifndef __KLEO_KEYFORMAILBOX_H__
+#define __KLEO_KEYFORMAILBOX_H__
+
+#include <QString>
+
+#include "job.h"
+
+#include <gpgme++/key.h>
+namespace GpgME
+{
+class Error;
+class KeyListResult;
+}
+
+namespace QGpgME
+{
+
+/**
+   @short Get the best key to use for a Mailbox
+
+   To use the keyformailboxjob, first obtain an instance from the
+   CryptoBackend and either exec it or start and
+   conncet the result() signals to a suitable slot.
+   The job will be automatically deleted in which
+   case the KeylistJob instance will have schedules it's own
+   destruction with a call to QObject::deleteLater().
+
+   The best key is defined as the key with a UID that has an
+   E-Mail that matches the mailbox provided. If multiple
+   keys are found the one with the highest validity is returned.
+
+   After result() is emitted, the
+   KeyListJob will schedule it's own destruction by calling
+   QObject::deleteLater().
+*/
+class QGPGME_EXPORT KeyForMailboxJob: public Job
+{
+    Q_OBJECT
+protected:
+    explicit KeyForMailboxJob(QObject *parent);
+
+public:
+    ~KeyForMailboxJob();
+
+    /**
+      Starts the operation. \a mailbox is the mailbox to
+      look for.
+
+      The result is the same as for the LocateKeysJob.
+
+      If \a canEncrypt is true, only keys that have a subkey for encryption
+      usage are returned. Use this if you need to select a
+      key for signing.
+    */
+    virtual GpgME::Error start(const QString &mailbox, bool canEncrypt = true) = 0;
+
+    virtual GpgME::KeyListResult exec(const QString &mailbox, bool canEncrypt, GpgME::Key &key, GpgME::UserID &uid) = 0;
+
+Q_SIGNALS:
+    /** The result. \a Key is the key found or a Null key.
+     *
+     * The userid is the uid where the mailbox matches.
+     *
+     * The auditlog params are always null / empty.
+     */
+    void result(const GpgME::KeyListResult &result, const GpgME::Key &key, const GpgME::UserID &uid, const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error());
+};
+
+}
+#endif
index 64146b8..23b9d93 100644 (file)
@@ -62,6 +62,7 @@ class ChangeOwnerTrustJob;
 class ChangePasswdJob;
 class AddUserIDJob;
 class SpecialJob;
+class KeyForMailboxJob;
 
 /** The main entry point for QGpgME Comes in OpenPGP and SMIME(CMS) flavors.
  *
@@ -145,6 +146,8 @@ public:
      * with both includeSigs and validate options.
      */
     virtual KeyListJob *locateKeysJob() const = 0;
+    /** Find the best key to use for a mailbox. */
+    virtual KeyForMailboxJob *keyForMailboxJob() const = 0;
 };
 
 /** Obtain a reference to the OpenPGP Protocol.
index 9fcbc8b..afb4f9c 100644 (file)
@@ -56,6 +56,7 @@
 #include "qgpgmechangeownertrustjob.h"
 #include "qgpgmechangepasswdjob.h"
 #include "qgpgmeadduseridjob.h"
+#include "qgpgmekeyformailboxjob.h"
 
 namespace
 {
@@ -377,6 +378,15 @@ public:
         context->setKeyListMode(GpgME::Extern | GpgME::Local | GpgME::Signatures | GpgME::Validate);
         return new QGpgME::QGpgMEKeyListJob(context);
     }
+
+    QGpgME::KeyForMailboxJob *keyForMailboxJob() const Q_DECL_OVERRIDE
+    {
+        GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol);
+        if (!context) {
+            return Q_NULLPTR;
+        }
+        return new QGpgME::QGpgMEKeyForMailboxJob(context);
+    }
 };
 
 }
diff --git a/lang/qt/src/qgpgmekeyformailboxjob.cpp b/lang/qt/src/qgpgmekeyformailboxjob.cpp
new file mode 100644 (file)
index 0000000..0702a36
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+    qgpgmekeyformailboxjob.cpp
+
+    This file is part of qgpgme, the Qt API binding for gpgme
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#include "qgpgmekeyformailboxjob.h"
+#include "qgpgmekeylistjob.h"
+
+#include <tuple>
+
+using namespace GpgME;
+using namespace QGpgME;
+
+QGpgMEKeyForMailboxJob::QGpgMEKeyForMailboxJob(Context *context)
+    : mixin_type(context)
+{
+    lateInitialization();
+}
+
+QGpgMEKeyForMailboxJob::~QGpgMEKeyForMailboxJob() {}
+
+static bool keyIsOk(const Key k)
+{
+    return !k.isExpired() && !k.isRevoked() && !k.isInvalid() && !k.isDisabled();
+}
+
+static bool uidIsOk(const UserID uid)
+{
+    return keyIsOk(uid.parent()) && !uid.isRevoked() && !uid.isInvalid();
+}
+
+static bool subkeyIsOk(const Subkey s)
+{
+    return !s.isRevoked() && !s.isInvalid() && !s.isDisabled();
+}
+
+static QGpgMEKeyForMailboxJob::result_type do_work(Context *ctx, const QString &mailbox, bool canEncrypt)
+{
+    /* Do a Keylisting. */
+    ctx->setKeyListMode(GpgME::Extern | GpgME::Local | GpgME::Signatures | GpgME::Validate);
+    std::vector<Key> keys;
+    QGpgMEKeyListJob *keylist = new QGpgMEKeyListJob(ctx);
+
+    KeyListResult result = keylist->exec(QStringList() << mailbox, false, keys);
+
+    if (result.error()) {
+        return std::make_tuple(result, Key(), UserID(), QString(), Error());
+    }
+
+    // This should ideally be decided by GnuPG and this Job changed
+    // to just call the according API in GpgME
+    // See: https://bugs.gnupg.org/gnupg/issue2359
+    Key keyC;
+    UserID uidC;
+    Q_FOREACH (const Key k, keys) {
+        if (canEncrypt && !k.canEncrypt()) {
+            continue;
+        }
+        /* First get the uid that matches the mailbox */
+        Q_FOREACH (const UserID u, k.userIDs()) {
+            if (QString::fromUtf8(u.email()).toLower() == mailbox.toLower()) {
+                if (uidC.isNull()) {
+                    keyC = k;
+                    uidC = u;
+                } else if ((!uidIsOk(uidC) && uidIsOk(u)) || uidC.validity() < u.validity()) {
+                    /* Validity of the new key is better. */
+                    uidC = u;
+                    keyC = k;
+                } else if (uidC.validity() == u.validity() && uidIsOk(u)) {
+                    /* Both are the same check which one is newer. */
+                    time_t oldTime = 0;
+                    Q_FOREACH (const Subkey s, keyC.subkeys()) {
+                        if ((canEncrypt && s.canEncrypt()) && subkeyIsOk(s)) {
+                            oldTime = s.creationTime();
+                        }
+                    }
+                    time_t newTime = 0;
+                    Q_FOREACH (const Subkey s, k.subkeys()) {
+                        if ((canEncrypt && s.canEncrypt()) && subkeyIsOk(s)) {
+                            newTime = s.creationTime();
+                        }
+                    }
+                    if (newTime > oldTime) {
+                        uidC = u;
+                        keyC = k;
+                    }
+                }
+            }
+        }
+    }
+    return std::make_tuple(result, keyC, uidC, QString(), Error());
+}
+
+Error QGpgMEKeyForMailboxJob::start(const QString &mailbox, bool canEncrypt)
+{
+    run(std::bind(&do_work, std::placeholders::_1, mailbox, canEncrypt));
+    return Error();
+}
+
+KeyListResult QGpgMEKeyForMailboxJob::exec(const QString &mailbox, bool canEncrypt, Key &key, UserID &uid)
+{
+    const result_type r = do_work(context(), mailbox, canEncrypt);
+    resultHook(r);
+    key = std::get<1>(r);
+    uid = std::get<2>(r);
+    return std::get<0>(r);
+}
+
+#include "qgpgmekeyformailboxjob.moc"
diff --git a/lang/qt/src/qgpgmekeyformailboxjob.h b/lang/qt/src/qgpgmekeyformailboxjob.h
new file mode 100644 (file)
index 0000000..02a16d3
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    qgpgmekeyformailboxjob.h
+
+    This file is part of libkleopatra, the KDE keymanagement library
+    Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB
+    This file is part of qgpgme, the Qt API binding for gpgme
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#ifndef __QGPGME_QGPGMEKEYFORMAILBOXJOB_H__
+#define __QGPGME_QGPGMEKEYFORMAILBOXJOB_H__
+#include "keyformailboxjob.h"
+
+#include "threadedjobmixin.h"
+
+#include <gpgme++/keylistresult.h>
+#include <gpgme++/key.h>
+
+namespace QGpgME
+{
+
+class QGpgMEKeyForMailboxJob
+#ifdef Q_MOC_RUN
+    : public KeyForMailboxJob
+#else
+    : public _detail::ThreadedJobMixin<KeyForMailboxJob, std::tuple<GpgME::KeyListResult, GpgME::Key, GpgME::UserID, QString, GpgME::Error> >
+#endif
+{
+    Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+    void slotFinished();
+#endif
+public:
+    explicit QGpgMEKeyForMailboxJob(GpgME::Context *context);
+    ~QGpgMEKeyForMailboxJob();
+
+    /**
+      Starts the operation. \a mailbox is the mailbox to
+      look for.
+
+      The result is the same as for the LocateKeysJob.
+
+      If \a canEncrypt is true, only keys that have a subkey for encryption
+      usage are returned. Use this if you need to select a
+      key for signing.
+    */
+    GpgME::Error start(const QString &mailbox, bool canEncrypt = true) Q_DECL_OVERRIDE;
+
+    GpgME::KeyListResult exec(const QString &mailbox, bool canEncrypt, GpgME::Key &key, GpgME::UserID &uid) Q_DECL_OVERRIDE;
+};
+
+}
+#endif
index 13495a8..85f6fa6 100644 (file)
@@ -55,12 +55,14 @@ 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)
+run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp
 
 nodist_t_keylist_SOURCES = $(moc_files)
 
 BUILT_SOURCES = $(moc_files)
 
-noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt
+noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt \
+    run-keyformailboxjob
 
 CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \
        gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \
diff --git a/lang/qt/tests/run-keyformailboxjob.cpp b/lang/qt/tests/run-keyformailboxjob.cpp
new file mode 100644 (file)
index 0000000..9ac7668
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    run-keyformailbox.cpp
+
+    This file is part of QGpgME's test suite.
+    Copyright (c) 2016 Intevation GmbH
+
+    QGpgME is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License,
+    version 2, as published by the Free Software Foundation.
+
+    QGpgME is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of this program with any edition of
+    the Qt library by Trolltech AS, Norway (or with modified versions
+    of Qt that use the same license as Qt), and distribute linked
+    combinations including the two.  You must obey the GNU General
+    Public License in all respects for all of the code used other than
+    Qt.  If you modify this file, you may extend this exception to
+    your version of the file, but you are not obligated to do so.  If
+    you do not wish to do so, delete this exception statement from
+    your version.
+*/
+
+#include "keyformailboxjob.h"
+#include "keylistjob.h"
+#include "protocol.h"
+
+#include "key.h"
+#include "keylistresult.h"
+
+#include <QDebug>
+
+
+int main(int argc, char **argv)
+{
+    QString mailbox;
+    if (argc == 2) {
+        mailbox = QString::fromLocal8Bit(argv[1]);
+    }
+
+    auto job = QGpgME::openpgp()->keyForMailboxJob();
+    GpgME::Key k;
+    GpgME::UserID uid;
+    job->exec(mailbox, true, k, uid);
+    qDebug() << "UID Name: " << uid.name() << " Mail: " << uid.email() << " id: " << uid.id();
+    qDebug() << "Key fpr: " << k.primaryFingerprint();
+    return 0;
+}